Tag Archives: Encrypting

Strict security for Plesk mail services

Plesk 12 comes with support voor Dovecot Secure IMAP server. This is a great improvement on the Courier IMAP server. I personally prefer Postfix for SMTP. You can configure Postfix in a very secure manner. In this post I will discuss how to configure Dovecot and Postfix and to configure Roundcube webmail for additional support.

Dovecot
Dovecot supports IMAP4 and POP3. I decided to disable POP3 as it is inferior to IMAP4. If you do want POP3 enabled you should alter the configuration. I disallowed a number of insecure ciphers. I disabled plaintext authentication as it is highly insecure. Note that even though you client is using SSL you can still be vulnerable to attack if Plain text authentication is enabled. Next I changed to directory for the certificate.

First install Dovecot if you haven’t done so. Establish a SSH connection to the server en vi the file:

/etc/dovecot/conf.d/01-servername.conf

01 makes it the last applied file. Adjust the content to your liking:

protocols = imap
ssl_cipher_list = EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH+aRSA+RC4:EECDH:EDH+aRSA:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4
ssl_prefer_server_ciphers = yes
disable_plaintext_auth = yes
ssl_cert = </etc/dovecot/private/certificate.pem
ssl_key = </etc/dovecot/private/key.pem

This configuration encrypts IMAP4 traffic, disabled plain text authentication and enables a verifiable certificate. It diables a number of insecure ciphers and prefers better ciphers.

Postfix
Postfix is used by a massive amount of mail servers. Postfix by default is not configured in a safe manner. To enable Postfix to contact the rest of the world in a safe way you should enable certain ciphers. Furthermore you shouldn’t configure your Postfix server with EDH Ephemeral Diffie–Hellman. Most servers don’t support it yet which would lead to undeliverable mails. Instead use the Diffie-Hellman key exchange. You first need to create a 512 bit key exchange parameter file and a 1024 bit key exchange parameter file. Please note that a larger key length will result in a serious CPU penalty. To generate the files enter the commands below.

openssl gendh -out /etc/postfix/dh_512.pem -2 512
openssl gendh -out /etc/postfix/dh_1024.pem -2 1024

Next configure Postfix’s main.cf file:

vi /etc/postfix/main.cf

Remove the conflicting lines and add the lines below:

# TLS parameters
smtpd_tls_cert_file = /etc/postfix/certificate_2014.pem
smtpd_tls_key_file = $smtpd_tls_cert_file
smtpd_tls_dh1024_param_file = /etc/postfix/dh_1024.pem
smtpd_tls_dh512_param_file = /etc/postfix/dh_512.pem
smtpd_tls_eecdh_grade = strong
smtpd_tls_protocols= !SSLv2, !SSLv3
smtpd_tls_mandatory_protocols= !SSLv2, !SSLv3
smtpd_tls_security_level=encrypt
smtpd_tls_mandatory_ciphers = high
tls_preempt_cipherlist = yes
smtpd_tls_mandatory_exclude_ciphers = aNULL, MD5 , DES, ADH, RC4, PSD, SRP, 3DES, eNULL
smtp_tls_security_level = may

This will not be the most secure configuration. But please keep in mind that enforcing very high security standards will come at a high price.

Roundcube
When you altered the configuration above you need to restart the service of Postfix and Dovecot:

/etc/init.d/postfix restart
/etc/init.d/dovecot restart

When that is done your default Roundcube won’t work no more. This can be fixed by doing the following:

vi /usr/share/psa-roundcube/config/defaults.inc.php

Change the following values:

// IMAP
// ----------------------------------

// The mail host chosen to perform the log-in.
// Leave blank to show a textbox at login, give a list of hosts
// to display a pulldown menu or set one host as string.
// To use SSL/TLS connection, enter hostname with prefix ssl:// or tls://
// Supported replacement variables:
// %n - hostname ($_SERVER['SERVER_NAME'])
// %t - hostname without the first part
// %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
// %s - domain name after the '@' from e-mail address provided at login screen
// For example %n = mail.domain.tld, %t = domain.tld
// WARNING: After hostname change update of mail_host column in users table is
//          required to match old user data records with the new host.
$config['default_host'] = 'ssl://hostname.TLD';
@include "/etc/psa-webmail/roundcube/mailhosts.php";

// TCP port used for IMAP connections
$config['default_port'] = 993;

// IMAP AUTH type (DIGEST-MD5, CRAM-MD5, LOGIN, PLAIN or null to use
// best server supported one)
$config['imap_auth_type'] = DIGEST-MD5;


// ----------------------------------
// SMTP
// ----------------------------------

// SMTP server host (for sending mails).
// To use SSL/TLS connection, enter hostname with prefix ssl:// or tls://
// If left blank, the PHP mail() function is used
// Supported replacement variables:
// %h - user's IMAP hostname
// %n - hostname ($_SERVER['SERVER_NAME'])
// %t - hostname without the first part
// %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
// %z - IMAP domain (IMAP hostname without the first part)
// For example %n = mail.domain.tld, %t = domain.tld
$config['smtp_server'] = 'tls://hostname.tld';

// SMTP port (default is 25; use 587 for STARTTLS or 465 for the
// deprecated SSL over SMTP (aka SMTPS))
$config['smtp_port'] = 587;

This will restore the Roundcube functionality.

Strict security on a Plesk Apache web server 2

In an addition to my previous post I would like to add a few updates and improvements.

HSTS

While it is possible to add a line in the conf file. You can also use a nifty function in Plesk. Since Plesk 11.5  configuring the web server per site is possible. But before I take you to heaven I would like to add a few side notes. Be sure that if you use the includesubdomains flag, that all your subdomains support HTTPS. You can of course configure this per site, but if a browser connects to the parent site and receives the HSTS header, it will automatically connect for a long time to all subdomain using HTTPS. If one of your subdomain doesn’t support HTTPS and the user visited the parent site you’ll have a problem. You can of course exclude the IncludeSubDomains flag.

When logging in the Plesk Panel site you can configure the webserver. Go to Websites and Domains en click on Expand. Next click on configure webserver.

Schermafbeelding 2014-10-01 om 11.18.55

 

Scroll down to the end of the page and add the following line in the HTTPS settings:

Schermafbeelding 2014-10-01 om 11.22.50

Please mind the includeSubDomains switch

Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"

CSP

I recently learned about CSP. This make it impossible to have malicious  XSS or other code being run from your site. For example if you have a script that is being referred to in the index of you site, it is harder to exploit the trust that you browser has in your site. You can very basically configure this using the same steps as above by adding another line in you HTTPS config

 

Header unset Content-Security-Policy
Header add Content-Security-Policy "default-src https: 'unsafe-inline' 'unsafe-eval';connect-src https: wss:"

Please note that this is a very basic way to configure CSP. To further tighten CSP you can read this site. To enable full CSP you can replace about code with:

Header unset Content-Security-Policy
Header add Content-Security-Policy "default-src 'self'"

Additional headers

Other headers that can strengthen the security are:

Header always set X-Content-Type-Options: nosniff
Header always set X-Frame-Options: deny
Header always set X-XSS-Protection: "1; mode=block"

Please note that these headers may alter you website functionality. For example X-Frame-Options: limits frame redering. So if you have code that runs in a frame, there will be no output. My advise is to play around with these headers in your test environment. Above headers may be also used in HTTP. So you can add them to the HTTP headers. This is unlike HTST which of course has something to do with secure transfer.

You configure them in the same way as the headers above:

Schermafbeelding 2014-10-01 om 11.43.50

In my next post I will get into HTTP Public Key Pinning. This I still have to figure out myself so if I have some spare time I will test around a little bit. The support for this feature isn’t very broad. Only predefined list are currently supported. As always IE doesn’t support it yet. Firefox supports it since version 32. Chrome supports it since 2011. However there is no mainstream support for it as of now. HPKP will however be supported in the future so I want to be sure that by the time it is supported, I already comply 🙂

The complete header looks like this:

Strict security on a Plesk Apache web server

There is an update for this post

To ensure secure SSL traffic you should always protect you server properly. Plesk isn’t really the best solution to handle such tasks. I found a way to protect a Plesk server better using SSL. My configuration is a Ubuntu 14.04 LTS server in combination with Plesk 12. If you have Ubuntu 12.04 LTS you’ll have problem protecting such a server. I’ll discuss this later on.

What you first need to do is to ensure that only secure ciphers are being used. A secure cipher is one that enables Forward Secrecy. If someone captured SSL traffic and succeeds to brute force it’s way into one package, he cannot use that key to decipher all the other packages. In other words if someone cracks open one package he would have to do the same thing for each package. If you use ciphers that don not  enable forward secrecy and someone cracks open one package he can open all the packages. Which makes it highly insecure.

Create a file on the following location:

/etc/apache2/conf-enabled/zz050-psa-disable-weak-ssl-ciphers.conf

Enter the text below to disable the unwanted ciphers. Please note that by disabling SSLv3 your IE6 users will not be able to connect anymore.

SSLProtocol all -SSLv2 -SSLv3
SSLHonorCipherOrder on
SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS"

Please also note that you need to have Apache 2.3 for the EECDH algorithm. Apache 2.3 is not by default installed on Ubuntu 12.04 LTS. So I would recommend to install Ubuntu 14.04 LTS on you server or any other distribution with Apache 2.4 support.

Next you should enable OCSP stapling. This is a lot quicker to check for revocations than CRL. If your server handles a lot of traffic I would definitely  enabled this feature. Open the file:

/etc/apache2/conf-enabled/security.conf

And append the following text:

SSLUseStapling on
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors off
SSLCACertificateFile /etc/ssl/certs/StartCom_Certification_Authority.pem
SSLStaplingCache shmcb:/var/run/ocsp(128000)

I only use one CA. If you have more than one CA your at the moment limited to only enter one. OCSP Stapling doesn’t support more than one CA. There is a new standard that will get rid of this problem. It is however not very well supported. Both clients and servers do rarely support it. You’ll have to wait for a bit.

Next you can enable HSTS (HTTP Strict Transport Security). This only work with Apache 2.2.3 and above. The way Plesk handles website isn’t really efficient for HSTS. Don’t get me wrong I absolutely love the way Plesk handles SNI and other offloading  and features but this is one that could be improved. You have to open each conf file for a website in Plesk.

Please note the update stated above!

First I’ll explain what HSTS is.  Imagine that you site enables HTTP requests and HTTPS requests. You have HTTP enabled to redirect to HTTPS. One of you users browses to you site and fails to directly go to secure site. Someone have created a fraudulent access point and redirects the site to another site. The user doesn’t mind the changes and enters his credentials. Well that account is compromised. Now HSTS tells the browser to connect to the https:// site for the upcoming year. Each time the user browses to that site the timer wil be reset to another year for that date.

Each new website gets a .conf file in the system directory. You will have to make sure that a certain text is added to that file.

If you have a default website for an IP address a file is created like to one below:

/var/www/vhosts/system/domain.tld/conf/httpd_ip_default.conf

If you use SNI Plesk creates the file below for you:

/var/www/vhosts/system/domain.tld/conf/httpd.conf

In the portion of the container below add the following line

 

<VirtualHost x.x.x.x:443 >

</VirtualHost>
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains"

This enables HSTS. But please not any change to you website settings and this file get overwritten. I created a shell script that checks the existence of the text and if it is not enabled it will enable it for you. I post that later on.

Sign your scripts

In some high security environments is it required to sign you scripts. To do so you need a code sign certificate. One of the cheapest around is the one of StartSSL costing you only $ 59,99 or roughly € 40 ~ € 45.

I requested a code sign certificate via their site. The advantage of signing scripts with a public certificate is obviously that the script is trusted and you won’t be prompted to approve the script.

To sign a script you need to have the code signing certificate installed and also you need the function Set-AuthenticodeSignature. It is highly recommended that you use a timestamp server. This will ensure that the code is signed when the certificate was valid. So if you certificate expired you won’t have to sign all you code again. StartSSL has a Timestamp Server, but you can use any timestamp server that you prefer. I were at the moment not able to sign my scripts using the StartSSL timestamp server. I use Globalsign at the moment. The certificate from this timestamp server is valid until 2024. If anyone uses your scripts by then, you’d done your job very well ;-).

$Cert=(dir cert:currentuser\my\ -CodeSigningCert)
Set-AuthenticodeSignature ".\Script.ps1" $Cert -IncludeChain All -TimestampServer "http://timestamp.globalsign.com/scripts/timstamp.dll"

Including the chain will ensure that any intermediate certificate authority will be trusted. Be sure to save you code in ANSI format and not the default Unicode:BigEndian that Powershell ISE uses. Notepad(++) will save in ANSI by default. You can use the regular Unicode if you have any diacritic stated.

Your script will be appended with some additional code with certificate information. Note that Powershell v3 will need SHA256 algorithm. Powershell v2 (if anyone still usses that) accepts scripts which are sign with anything up to SHA1. You can specify the algorithm you want to use by entering -HashAlgorithm SHA512. By default in v3 and up it is SHA256.

Encrypt values using AES RSA in Powershell

You can encrypt a password so that only under your account it can be decrypted. If however you need some other user to decrypt the data the code is worthless. You can use different code for this case. You need a certificate with private key. It can be a certificate that is self signed. You can use byte values of a maximum van 32 (equals 256 bit). I would recommend using a 32 Byte value. Get the thumbprint value using the following code:

Get-Item -Path Cert:\CurrentUser\My\*

Of course you can also use a certificate that is installed on the local machine. For the sake of better security I would use a certificate that is installed in the CurrentUser part of the certificate store.

If you know the thumbprint of the certificate, state that value in the $thumbprint string. Enter the plaintext value which you want to encrypt in the string $Securestring. Configure the Export-Clixml path to you liking. You can change the name of the XML file without voiding the abillity to decrypt.

try
{
    $secureString = 'StrongPassword' | 
                    ConvertTo-SecureString -AsPlainText -Force

    # Generate our new 32-byte AES key.  I don't recommend using Get-Random for this; the System.Security.Cryptography namespace
    # offers a much more secure random number generator.

    $key = New-Object byte[](32)
    $rng = [System.Security.Cryptography.RNGCryptoServiceProvider]::Create()

    $rng.GetBytes($key)

    $encryptedString = ConvertFrom-SecureString -SecureString $secureString -Key $key

    # This is the thumbprint of a certificate on my test system where I have the private key installed.Note that the thumbprint value is CASE SENSITIVE

    $thumbprint = 'D180EA99616A925E716278635E29159BC7105663'
    $cert = Get-Item -Path Cert:\CurrentUser\My\$thumbprint -ErrorAction Stop

    $encryptedKey = $cert.PublicKey.Key.Encrypt($key, $true)

    $object = New-Object psobject -Property @{
        Key = $encryptedKey
        Payload = $encryptedString
    }

    $object | Export-Clixml .\encryptionTest2.xml

}
finally
{
    if ($null -ne $key) { [array]::Clear($key, 0, $key.Length) }

You can decrypt the value securely using the following code:

try
{
    $object = Import-Clixml -Path .\encryptionTest2.xml

    $thumbprint = 'D180EA99616A925E716278635E29159BC7105663'
    $cert = Get-Item -Path Cert:\CurrentUser\My\$thumbprint -ErrorAction Stop

    $key = $cert.PrivateKey.Decrypt($object.Key, $true)

    $secureString = $object.Payload | ConvertTo-SecureString -Key $key 
	
}
finally
{
    if ($null -ne $key) { [array]::Clear($key, 0, $key.Length) }
}

$cred = New-Object System.Management.Automation.PSCredential(Useraccount, $secureString)

Now you can run command’s under an account without having to compromise the password easily. You need to have the certificate to decrypt.  Don’t try to encrypt the username also. Powershell does not accept secure usernames somehow.  An example of how to use this would be:

Import-Module ActiveDirectory
$Username = [Environment]::UserName
Get-ADUser -Identity $Username -Credential $Cred

To troubleshoot you can decrypt the password in plain text using the following code. Please note that this leaves the unencrypted password in the memory waiting to be exploited.

$cred = New-Object System.Management.Automation.PSCredential('Username', $secureString)
$plainText = $cred.GetNetworkCredential().Password
Write-Host $Plaintext

Encrypt Values using DPAPI

You can encrypt passwords for your account only using DPAPI. You need the function on this site.

Import the module. On some hardened systems using:

Import-Module '.\Modulename.psm1' -Force

Next encrypt the password using the following command:

$secureString = Read-Host -AsSecureString "Enter a secret password." 

# You can pass basically anything as the Entropy value, but I'd recommend sticking to simple value types (including strings),
# or arrays of those types, to make sure that the binary serialization of your entropy object doesn't change between
# script executions.  Here, we'll use Pi.  Edit:  The latest version of the code enforces the use of the recommended simple
# types, unless you also use the -Force switch.

$secureString | ConvertFrom-SecureString -Entropy ([Math]::PI) | Out-File .\storedPassword.txt

You can use it by decrypting the password as a secure string using the following code:

$newSecureString = Get-Content -Path .\storedPassword.txt | ConvertTo-SecureString -Entropy ([Math]::PI)

You can decrypt the password as plain text using the following code:

$newSecureString = Get-Content -Path .\storedPassword.txt | ConvertTo-SecureString -Entropy ([Math]::PI)
$newSecureString | ConvertFrom-SecureString -AsPlainText -Force