As developers and system administrators come together to form DevOps, it’s important to not exclude security. Security is an extremely important topic especially in today’s day and age and is one that we can begin to include in our everyday PowerShell code.
Injecting security in PowerShell code is a deep topic and one that could not be completed in a single chapter let alone a single book. But, in this chapter, you’ll learn some tips to take care of some of the low-hanging fruit easily obtained by using some best practices.
Sign Scripts
PowerShell has a built-in method to cryptographically sign all scripts to ensure they are not tampered with. Signing a script adds a cryptographic hash at the bottom of the script. When an execution policy is set to RemoteSigned or AllSigned , PowerShell will not allow the script to run if it detects the code has been modified since it was last signed.
Let’s quickly cover how you would sign a PowerShell script. To do so, you must first have a certificate capable of code signing. You can either use a public certificate or a self-signed one. Let’s create a self-signed certificate for simplicity using the New-SelfSignedCertificate cmdlet.
If you open up the script you just signed, you’ll see the large signature at the bottom. Now if you run this script on a computer that has an execution policy requiring signed certificates and that computer has your generated certificates, PowerShell will execute the script.
Tip Source: https://twitter.com/brentblawat
Further Learning
Use Scriptblock Logging
It’s critical to know what code is being executed in your environment. Unfortunately, if you download a script from the Internet, click a malicious link or a user gets a phishing email, that code may be malicious.
By enabling scriptblock logging in your environment, you can see, down to the scriptblock level, exactly what that code is doing and developing a proper audit trail.
Further Learning
Never Store Sensitive Information in Clear Text in Code
This should go without saying but saving passwords, private keys, API keys, or any other sensitive information in code is a bad idea. PowerShell allows you many different ways to encrypt this information and decrypt it, when necessary.
Use the Export and Import-CliXml commands to encrypt and decrypt objects with sensitive information like credentials. Use secure strings rather than plaintext strings, generate your own cryptographic keys, and more with PowerShell. There are lots of ways to encrypt and decrypt sensitive information with PowerShell.
Perhaps you need to pass a PSCredential object to a service to authenticate. Typically, you’ve been using the Get-Credential cmdlet to create this object by prompting you for a username and password. You’d now like to automate this process and authenticate without any user interaction.
You now have MySecretPassword stored in plaintext inside of the script. Don’t do this. Instead, save PSCredential object to disk encrypted using Export-CliXml.
You now have a PSCredential object stored in $credential that’s exactly the same as if you obtained it via other means. And, as an added bonus, it requires no interaction and is encrypted.
Further Learning
Don’t Use Invoke-Expression
Using the Invoke-Expression command can open up your code to code injection attacks. The Invoke-Expression command allows you to treat any type of string as executable code. This means that whatever expression you pass to Invoke-Expression, PowerShell will gladly execute it under whatever context it’s running in. Although executing the expression you intend works great, what happens when you open up the code to others?
You’ve got a bad day on your hands. By invoking expressions blindly and allowing PowerShell to invoke any code passed to it, you’re allowing any kind of code to run which is a terrible practice!
Further Learning
Use PowerShell Constrained Language Mode
If you need to allow junior users, employees in your company, or service applications the ability to run PowerShell commands, you need to ensure that access is least privilege. There’s no need to allow running commands others do not need and may accidentally or purposefully introduce security issues.
PowerShell has a mode called constrained language mode that allows you to provide access to a PowerShell environment but not allow access to all commands and modules. Constrained language mode allows you to granularly define activities as allowed and disallowed giving you tight control over what can be done.