Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
January 12, 2022 09:01 pm GMT

Use Windows Data Protection API with Python for handling credentials.

As a IT Tech, I do alot of automation scripting, both in Powershell and Python against various systems and Ive never liked how I had to handle credentials in scripts.

I dont want to have any credentials or API-keys in plain text on a server that others have access to, so I saved it as environment variables like most of us do.
That works fine, but when you have hundreds of variables for email accounts, API-keys and SFTP accounts it can get messy.

When I looked for a better solution I found this gem for Powershell!

All commands below are run from PowerShell.

Prompt for Username and Password and save to file

PS C:\> Get-Credential | Export-Clixml -Path "cred.xml"

Import the credentials from a file to a PSCredential object.

PS C:\> $cred = Import-Clixml -Path "cred.xml"PS C:\> $credUserName                     Password--------                     --------samkling System.Security.SecureStringPS C:\> ConvertFrom-SecureString $cred.password -AsPlainTextpassword
ConvertFrom-SecureString -AsPlainText requires PowerShell 7.0.
Export-Clixml only exports encrypted credentials on Windows.

The Export-Clixml cmdlet encrypts credential objects by using the Windows Data Protection API . The encryption ensures that only your user account on only that computer can decrypt the contents of the credential object. The exported CLIXML file can't be used on a different computer or by a different user.

I now store the credentials neatly, and secure in a credentials.xml file in the same directory as the actual script. Anyone can access the credential file and the script, but they wont be able to decrypt

. company1-sftp-script   download-files-newer-than-1-day.ps1   credentials.xml company2-sftp-script    download-files-newer-than-1-day.ps1    credentials.xml

How can we use the same method in Python?

Sadly there is no Export-Clixml/Import-Clixml equalent for Python so we will have to build it ourselves.

First we need to have access Windows Data Protection API. There are several ways, I use pywin32.

PS C:\> pip install pywin32

And then we need to create two files in python.

# export_clixml.pyimport win32cryptimport binasciiimport sysdef export_clixml(username, password):    # encrypt the password with DPAPI.    crypted_password = win32crypt.CryptProtectData(        password.encode("utf-16-le"), None, None, None, None, 0    )    # Do some magic to return the password in the exact same format as if you would use Powershell.    password_secure_string = binascii.hexlify(crypted_password).decode()    # Use the same xml format as for powershells Export-Clixml, just replace values for username and password.    xml = f"""<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">    <Obj RefId="0">        <TN RefId="0">        <T>System.Management.Automation.PSCredential</T>        <T>System.Object</T>        </TN>        <ToString>System.Management.Automation.PSCredential</ToString>        <Props>        <S N="UserName">{username}</S>        <SS N="Password">{password_secure_string}</SS>        </Props>    </Obj>    </Objs>"""    return xmlif __name__ == "__main__":    if len(sys.argv) == 3:        # Dont do this, It's just so that we can pipe the output to file to mimic the powershells version.        print(export_clixml(sys.argv[1], sys.argv[2]))
# import_clixml.pyimport win32cryptimport binasciiimport sysdef import_clixml(filename):    with open(filename, "r", encoding="utf-8") as f:        xml = f.read()        # Extract username and password from the XML since thats all we care about.        username = xml.split('<S N="UserName">')[1].split("</S>")[0]        password_secure_string = xml.split('<SS N="Password">')[1].split("</SS>")[0]        # CryptUnprotectDate returns two values, description and the password,         # we dont care about the description, so we use _ as variable name.        _, decrypted_password_string = win32crypt.CryptUnprotectData(            binascii.unhexlify(password_secure_string), None, None, None, 0        )        return f"{username}, {decrypted_password_string.decode()}"if __name__ == "__main__":    # We use sys args just to mimic the powershell version.    if len(sys.argv) == 2:        print(import_clixml(sys.argv[1]))

Lets try it out and see if we can use Powershells Export-Clixml and Pythons Import-Clixml.

PS C:\> Get-Credential | Export-Clixml -Path powershell_cred.xml PowerShell credential requestEnter your credentials.User: samklingPassword: passwordPS C:\> py .\Import_Clixml.py .\powershell_cred.xmlsamkling, password

Sweet, so it returned the correct username and password decrypted.

What about the other way around? From Python to Powershell?

PS C:\> $cred = Import-Clixml -Path .\python_cred.xmlPS C:\> $credUserName                     Password--------                     --------samkling System.Security.SecureStringPS C:\> ConvertFrom-SecureString $cred.password -AsPlainTextpassword

How cool is that!


Original Link: https://dev.to/samklingdev/use-windows-data-protection-api-with-python-for-handling-credentials-5d4j

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To