Differences

This shows you the differences between the selected revisions of the page.

guide_protecting_credentials_for_automation 2016-11-23 guide_protecting_credentials_for_automation 2024-04-22 (current)
Line 4: Line 4:
  * The script/code is often stored in a revision control system, making the credentials easily accessible.   * The script/code is often stored in a revision control system, making the credentials easily accessible.
  * The script/code may often need to be accessible on the production system for review or auditing purposes or reuse, while the credentials should not.   * The script/code may often need to be accessible on the production system for review or auditing purposes or reuse, while the credentials should not.
 +
 +There is no way to store passwords in script in an encrypted way. In general, it is not possible to encrypt any kind of information in a way that still allows for its use in an automatic way. If WinSCP should be able to decrypt the information, anyone can.((For a real encryption, one needs to use a key. And the key needs to be stored somewhere again. It's the chicken or the egg problem.))
Solution is to separate the credentials from the script/code into a configuration file. While the script/code without explicit credentials can be safely stored into a revision system and be otherwise accessible, the configuration file should be protected as much as possible. Particularly its file permissions should be restricted only to administrators (for writing) and user under which the script/code runs (for reading). The configuration file can also be encrypted, for example with [[wp>Encrypting_File_System|built-in NTFS filesystem-level encryption]]. Solution is to separate the credentials from the script/code into a configuration file. While the script/code without explicit credentials can be safely stored into a revision system and be otherwise accessible, the configuration file should be protected as much as possible. Particularly its file permissions should be restricted only to administrators (for writing) and user under which the script/code runs (for reading). The configuration file can also be encrypted, for example with [[wp>Encrypting_File_System|built-in NTFS filesystem-level encryption]].
Line 11: Line 13:
In [[scripting|script]], you can replace actual credentials with reference to environment variables. You can then call WinSCP from a batch file that sets these variables. The batch file itself then serves as a "configuration file". In [[scripting|script]], you can replace actual credentials with reference to environment variables. You can then call WinSCP from a batch file that sets these variables. The batch file itself then serves as a "configuration file".
-For example, following script (''example.txt''):+For example, the following script (''example.txt'')((Using [[scriptcommand_open#username|''-username'']] and [[scriptcommand_open#password|''-password'']] switches instead of specifying credentials in [[session_url|session URL]], because the switches do not require the values to be [[session_url#special|URL-encoded]].)):
<code winscp> <code winscp>
-open sftp://%USERNAME%:%PASSWORD%@example.com+open -username=%USERNAME% -password=%PASSWORD% sftp://example.com/
... ...
</code> </code>
Line 25: Line 27:
set PASSWORD=mypassword set PASSWORD=mypassword
winscp.com /script=example.txt winscp.com /script=example.txt
 +</code>
 +----
 +Another way is to store the password to a separate file and use [[scriptcommand_open#passwordsfromfiles|''-passwordsfromfiles'']]:
 +<code winscp>
 +open -password=C:\path\password.txt -passwordsfromfiles sftp://username@example.com/
</code> </code>
Line 37: Line 44:
<code xml> <code xml>
<Configuration> <Configuration>
-  <UserName>helpd</UserName> +  <UserName>martin</UserName> 
-  <Password>temp67</Password>+  <Password>mypassword</Password>
</Configuration> </Configuration>
</code> </code>
Line 51: Line 58:
$sessionOptions = New-Object WinSCP.SessionOptions -Property @{ $sessionOptions = New-Object WinSCP.SessionOptions -Property @{
    Protocol = [WinSCP.Protocol]::Sftp     Protocol = [WinSCP.Protocol]::Sftp
-    HostName = "\\10.0.101.220\d$"+    HostName = "example.com"
    UserName = $config.Configuration.UserName     UserName = $config.Configuration.UserName
    Password = $config.Configuration.Password     Password = $config.Configuration.Password
Line 61: Line 68:
You can also leverage Windows Data Protection API to encrypt the password in the %%XML%% file. You can also leverage Windows Data Protection API to encrypt the password in the %%XML%% file.
-To encrypt the password use ''[[ps>microsoft.powershell.security/convertfrom-securestring|ConvertFrom-SecureString]]'' cmdlet:+If you want to encrypt the password within the configuration file, you can use use ''[[ps>microsoft.powershell.security/convertfrom-securestring|ConvertFrom-SecureString]]'' cmdlet. Put the following code to an ad-hoc script (or an interactive PowerShell console):
<code powershell> <code powershell>
Line 78: Line 85:
</code> </code>
-To decrypt the password, use ''[[ps>microsoft.powershell.security/convertto-securestring|ConvertTo-SecureString]]'' cmdlet and assign the resulting ''[[https://msdn.microsoft.com/en-us/library/system.security.securestring.aspx|SecureString]]'' to ''SessionOptions.SecurePassword'':+To decrypt the password, use ''[[ps>microsoft.powershell.security/convertto-securestring|ConvertTo-SecureString]]'' cmdlet and assign the resulting ''[[dotnet&gt;system.security.securestring|SecureString]]'' to [[library_sessionoptions#securepassword|''SessionOptions.SecurePassword'']], instead of using plain text ''SessionOptions.Password'':
<code powershell> <code powershell>
Line 114: Line 121:
Set the //Copy to Output Directory// property of the file to //Copy if newer// and the //Build Action// to //Content// to have the new configuration file correctly deployed. Set the //Copy to Output Directory// property of the file to //Copy if newer// and the //Build Action// to //Content// to have the new configuration file correctly deployed.
-To read the settings from the configuration file use ''[[https://msdn.microsoft.com/en-us/library/system.configuration.configurationmanager.appsettings.aspx|ConfigurationManager.AppSettings]]'':((You need to reference the ''System.configuration'' assembly in your project to use the ''ConfigurationManager'' class.))+To read the settings from the configuration file use ''[[dotnet&gt;system.configuration.configurationmanager.appsettings|ConfigurationManager.AppSettings]]'':((You need to reference the ''System.configuration'' assembly in your project to use the ''ConfigurationManager'' class.))
<code csharp> <code csharp>
Line 128: Line 135:
You can also leverage Windows Data Protection API to encrypt the password in the XML file. You can also leverage Windows Data Protection API to encrypt the password in the XML file.
-To encrypt the password use PowerShell ''ConvertFrom-SecureString'' cmdlet:+If you want to encrypt the password within the configuration file, you can use use PowerShell ''ConvertFrom-SecureString'' cmdlet:
<code> <code>
Line 146: Line 153:
</code> </code>
-To decrypt the password, use ''[[https://msdn.microsoft.com/en-us/library/xh68ketz.aspx|ProtectedData.Unprotect]]'':((You need to reference the ''System.Security'' assembly in your project to use the ''ProtectedData'' class.))+To decrypt the password, use ''[[dotnet&gt;system.security.cryptography.protecteddata.unprotect|ProtectedData.Unprotect]]'':((You need to reference the ''System.Security'' assembly in your project to use the ''ProtectedData'' class.))
<code csharp> <code csharp>
string hex = ConfigurationManager.AppSettings["Password"]; string hex = ConfigurationManager.AppSettings["Password"];
-byte[] bytes = Enumerable.Range(0, hex.Length / 2).Select(x => Convert.ToByte(hex.Substring(x * 2, 2), 16)).ToArray();+byte[] bytes = 
 + ···Enumerable.Range(0, hex.Length / 2). 
 +········Select(x => Convert.ToByte(hex.Substring(x * 2, 2), 16)).ToArray();
byte[] decrypted = ProtectedData.Unprotect(bytes, null, DataProtectionScope.CurrentUser); byte[] decrypted = ProtectedData.Unprotect(bytes, null, DataProtectionScope.CurrentUser);
sessionOptions.Password = Encoding.Unicode.GetString(decrypted); sessionOptions.Password = Encoding.Unicode.GetString(decrypted);

Last modified: by 217.64.22.114