Fixes the double-login problem and making sure authorization usernames/passwords are not sent in cleartext unencrypted when using basic/digest authentication. This code is really, really nice because it fixes multiple issues with almost every other SSL redirect technique in htaccess files. (I discovered this one on my own). See also: Additional https/ssl information
SSLOptions +StrictRequire SSLRequireSSL SSLRequire %{HTTP_HOST} eq "google.com" ErrorDocument 403 https://google.com
The problem with most techniques is REWRITING the URL.. so if you check the request to see if its being sent on port 443... guess what? in the interim it got sent! Most of the times the double login prompt error happens because users type in http://secureurl.com
instead of https://secureurl.com
. Most modern browsers automatically request the /favicon.ico
file from the resource. In this case the resource is http instead of https like it should be.
Now with some of the other techniques below you can solve this problem, but you will still face a potential ssl security issue. What if a user types in https://secureurl.com:80 There are a lot of these types of weird ways to bypass security so I recommend using the SSLRequireSSL
option always.
This will check to make sure that the connection IS using SSL, or it will fail. This works regardless of if your serving SSL on port 443, 80, 81, etc. This is the most secure setting for SSL logins. This also fixes having to type in the username and password twice by requiring the HTTP_HOST to match the HTTP_HOST that your SSL certificate is set-up for, in the case above, the SSL is for https://google.com
not https://www.google.com
. If any of the required conditions are not met the server returns a 403 Forbidden Status Code (before mod_rewrite starts) and the ErrorDocument directive catches the 403 to send the visitor a Redirect to https://google.com
SetEnvIf
can be used to set/unset various variables that control apache via .htaccess
or httpd.conf
.
SetEnvIf User-Agent ".*MSIE.*" nokeepalive
SetEnvIf User-Agent ".*MSIE.*" ssl-unclean-shutdown
SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown
This can be necessary for some cgi scripts served over SSL.
SSLOptions +StdEnvVars
Any htaccess rewrite examples should begin with the following Options and the rewriterules at the top.
Options +FollowSymLinks RewriteEngine On RewriteBase /
Here are several methods to rewrite ssl requests
The HTTPS variable is always present, even if mod_ssl isn't loaded!
RewriteCond %{HTTPS} !=on RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [R,L]
The SERVER_PORT variable is always present, and generally SSL runs on certain ports like 443.
RewriteCond %{SERVER_PORT} !^443$ RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [R,L]
RewriteCond %{SERVER_PORT} ^80$ RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [R=301,L]
RewriteRule ^/normal/secure(/.*) https://%{HTTP_HOST}$1 [R=301,L]
RewriteCond %{HTTPS} !=on RewriteRule ^(/secure/.*) https://%{HTTP_HOST}$1 [R=301,L]
This lets you use hyperlinks of the form:
/document.html:SSL --> https://google.com/document.html
and
/document.html:NOSSL --> http://google.com/document.html
RewriteRule ^/(.*):SSL$ https://%{SERVER_NAME}/$1 [R,L] RewriteRule ^/(.*):NOSSL$ http://%{SERVER_NAME}/$1 [R,L]
Don't forget about the mod_alias redirect directives!
See also: Redirect with redirectmatch
Redirect / https://google.com/
Redirect 301 / https://google.com/
See also: Redirect with redirectmatch
Source: Requiring SSL client authentication in a user friendly way in Apache. I'm using "require" somewhat loosely here, as that's the first thing we are going to change in our configuration. When you use the SSLVerifyClient directive with the require value, it really means require. So, how do we get around this? We change the SSLVerifyClient directive to the optional value. The key is making optional still mean require. Our goal is to redirect users to help documentation when SSL client authentication fails. We can do this by using mod_rewrite and environment variables from mod_ssl. Here's how to configure this in Apache:
SSLOptions +StdEnvVars SSLVerifyClient optional SSLVerifyDepth 3 RewriteEngine On RewriteCond %{SSL:SSL_CLIENT_VERIFY} !^SUCCESS$ RewriteRule .* /help/ssl-client-auth-required.html [L]
In this configuration, any request that doesn't have a valid client certificate will be redirected to a help file. Optional, yet required politely. Don't forget to be polite internationally, if that is a requirement! You should configure Apache to serve the help document based on the user's language. I'm going to avoid this portion of the topic for now. I'll go into this in a future article.
The mod_ssl module provides a lot of SSL information as additional environment variables to the SSI and CGI namespace. The generated variables are listed in the table below.
For a full list including sample values, view the Apache Variable Cheatsheet.
Variable Name: | Value Type: | Description: |
---|---|---|
HTTPS | flag | HTTPS is being used. |
SSL_PROTOCOL | string | The SSL protocol version (SSLv2, SSLv3, TLSv1) |
SSL_SESSION_ID | string | The hex-encoded SSL session id |
SSL_CIPHER | string | The cipher specification name |
SSL_CIPHER_EXPORT | string | true if cipher is an export cipher |
SSL_CIPHER_USEKEYSIZE | number | Number of cipher bits (actually used) |
SSL_CIPHER_ALGKEYSIZE | number | Number of cipher bits (possible) |
SSL_VERSION_INTERFACE | string | The mod_ssl program version |
SSL_VERSION_LIBRARY | string | The OpenSSL program version |
SSL_CLIENT_M_VERSION | string | The version of the client certificate |
SSL_CLIENT_M_SERIAL | string | The serial of the client certificate |
SSL_CLIENT_S_DN | string | Subject DN in client's certificate |
SSL_CLIENT_S_DN_ x509 | string | Component of client's Subject DN |
SSL_CLIENT_I_DN | string | Issuer DN of client's certificate |
SSL_CLIENT_I_DN_ x509 | string | Component of client's Issuer DN |
SSL_CLIENT_V_START | string | Validity of client's certificate (start time) |
SSL_CLIENT_V_END | string | Validity of client's certificate (end time) |
SSL_CLIENT_A_SIG | string | Algorithm used for the signature of client's certificate |
SSL_CLIENT_A_KEY | string | Algorithm used for the public key of client's certificate |
SSL_CLIENT_CERT | string | PEM-encoded client certificate |
SSL_CLIENT_CERT_CHAIN n | string | PEM-encoded certificates in client certificate chain |
SSL_CLIENT_VERIFY | string | NONE , SUCCESS , GENEROUS or FAILED: reason |
SSL_SERVER_M_VERSION | string | The version of the server certificate |
SSL_SERVER_M_SERIAL | string | The serial of the server certificate |
SSL_SERVER_S_DN | string | Subject DN in server's certificate |
SSL_SERVER_S_DN_ x509 | string | Component of server's Subject DN |
SSL_SERVER_I_DN | string | Issuer DN of server's certificate |
SSL_SERVER_I_DN_ x509 | string | Component of server's Issuer DN |
SSL_SERVER_V_START | string | Validity of server's certificate (start time) |
SSL_SERVER_V_END | string | Validity of server's certificate (end time) |
SSL_SERVER_A_SIG | string | Algorithm used for the signature of server's certificate |
SSL_SERVER_A_KEY | string | Algorithm used for the public key of server's certificate |
SSL_SERVER_CERT | string | PEM-encoded server certificate |
[ where x509 is a component of a X.509 DN: C,ST,L,O,OU,CN,T,I,G,S,D,UID,Email
]
There are several ways to get the ssl logs setup the way you like.
When mod_ssl is built into Apache or at least loaded (under DSO situation) additional functions exist for the Custom Log Format of mod_log_config. First there is an additional %{varname}
extension format function which can be used to expand any variables provided by any module.
Note these can only go in the httpd.conf
file, not in .htaccess.
CustomLog logs/ssl_request_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x "%r" %b"
CustomLog logs/ssl_access_log commonvhostssl
These create 2 new log formats you can then use with the CustomLog
directive.
LogFormat "%h %l %{SSL_CLIENT_S_DN_Email}x %t "%r" %>s %b "%{Referer}i" "%{User-agent}i"" commonssl LogFormat "%v %h %l %{SSL_CLIENT_S_DN_Email}x %t "%r" %>s %b "%{Referer}i" "%{User-agent}i"" commonvhostssl
Based on the request you can choose to log or not to log.
This will set the dontlog
variable for requests ending in common image extensions.
SetEnvIfNoCase Request_URI .(?:gif|jpe?g|flv|swf|ico)$ dontlog
This will only log requests when the dontlog
variable is not set.
CustomLog logs/ssl_access_log commonvhostssl env=!dontlog
Extensive information on mod_ssl is provided at: modssl.org: SSL Reference, including information about SSLPassPhraseDialog
, SSLMutex
, SSLRandomSeed
, SSLSessionCache
, SSLSessionCacheTimeout
, SSLEngine
, SSLProtocol
, SSLCipherSuite
, SSLCertificateFile
, SSLCertificateKeyFile
, SSLCertificateChainFile
, SSLCACertificatePath
, SSLCACertificateFile
, SSLCARevocationPath
, SSLCARevocationFile
, SSLVerifyClient
, SSLVerifyDepth
, SSLLog
, SSLLogLevel
, SSLOptions
, SSLRequireSSL
, SSLRequire
, among other valuable info.
This directive toggles the usage of the SSL/TLS Protocol Engine. This is usually used inside a section to enable SSL/TLS for a particular virtual host. By default the SSL/TLS Protocol Engine is disabled for both the main server and all configured virtual hosts.
SSLEngine on
This directive can be used to control various run-time options on a per-directory basis. Normally, if multiple SSLOptions could apply to a directory, then the most specific one is taken completely; the options are not merged. However if all the options on the SSLOptions directive are preceded by a plus (+) or minus (-) symbol, the options are merged. Any options preceded by a + are added to the options currently in force, and any options preceded by a - are removed from the options currently in force.
xxj31ZMTZzkVA
, which is the DES-encrypted version of the word `password''. Those who live under MD5-based encryption (for instance under FreeBSD or BSD/OS, etc.) should use the following MD5 hash of the same word: $1$OXLyS...$Owx8s2/m9/gfkcRVXzgoE/
.Satisfy any
directive is used, and other access restrictions are passed, denial of access due to SSLRequireSSL or SSLRequire is overridden (because that's how the Apache Satisfy mechanism should work.) But for strict access restriction you can use SSLRequireSSL and/or SSLRequire in combination with an SSLOptions +StrictRequire
. Then an additional Satisfy Any
has no chance once mod_ssl has decided to deny access.SSLOptions +FakeBasicAuth -StrictRequire +StdEnvVars +CompatEnvVars -ExportCertData
This directive specifies a general access requirement which has to be fulfilled in order to allow access. It's a very powerful directive because the requirement specification is an arbitrarily complex boolean expression containing any number of access checks.
This function takes one string argument and expands to the contents of the file. This is especially useful for matching this contents against a regular expression, etc. Notice that expression is first parsed into an internal machine representation and then evaluated in a second step. Actually, in Global and Per-Server Class context expression is parsed at startup time and at runtime only the machine representation is executed. For Per-Directory context this is different: here expression has to be parsed and immediately executed for every request.
SSLRequire %{REMOTE_ADDR} =~ m/^192.76.162.[0-9]+$/
SSLRequire ( %{SSL_CIPHER} !~ m/^(EXP|NULL)-/ and %{SSL_CLIENT_S_DN_O} eq "Snake Oil, Ltd." and %{SSL_CLIENT_S_DN_OU} in {"Staff", "CA", "Dev"} and %{TIME_WDAY} >= 1 and %{TIME_WDAY} <= 5 and %{TIME_HOUR} >= 8 and %{TIME_HOUR} <= 20 ) or %{REMOTE_ADDR} =~ m/^192.76.162.[0-9]+$/
This directive forbids access unless HTTP over SSL (i.e. HTTPS) is enabled for the current connection. This is very handy inside the SSL-enabled virtual host or directories for defending against configuration errors that expose stuff that should be protected. When this directive is present all requests are denied which are not using SSL. Example SSLRequireSSL
This directive sets the "user" field in the Apache request object. This is used by lower modules to identify the user with a character string. In particular, this may cause the environment variable REMOTE_USER to be set. The varname can be any of the SSL environment variables.
SSLUserName SSL_CLIENT_S_DN_CN
This directive sets the Certificate verification level for the Client Authentication. Notice that this directive can be used both in per-server and per-directory context. In per-server context it applies to the client authentication process used in the standard SSL handshake when a connection is established. In per-directory context it forces a SSL renegotation with the reconfigured client verification level after the HTTP request was read but before the HTTP response is sent.
In practice only levels none and require are really interesting, because level optional doesn't work with all browsers and level optional_no_ca is actually against the idea of authentication (but can be used to establish SSL test pages, etc.)
SSLVerifyClient require
This directive sets how deeply mod_ssl should verify before deciding that the clients don't have a valid certificate. Notice that this directive can be used both in per-server and per-directory context. In per-server context it applies to the client authentication process used in the standard SSL handshake when a connection is established. In per-directory context it forces a SSL renegotation with the reconfigured client verification depth after the HTTP request was read but before the HTTP response is sent. The depth actually is the maximum number of intermediate certificate issuers, i.e. the number of CA certificates which are max allowed to be followed while verifying the client certificate. A depth of 0 means that self-signed client certificates are accepted only, the default depth of 1 means the client certificate can be self-signed or has to be signed by a CA which is directly known to the server (i.e. the CA's certificate is under SSLCACertificatePath), etc.
SSLVerifyDepth 10
This complex directive uses a colon-separated cipher-spec string consisting of OpenSSL cipher specifications to configure the Cipher Suite the client is permitted to negotiate in the SSL handshake phase. Notice that this directive can be used both in per-server and per-directory context. In per-server context it applies to the standard SSL handshake when a connection is established. In per-directory context it forces a SSL renegotation with the reconfigured Cipher Suite after the HTTP request was read but before the HTTP response is sent.
An SSL cipher can also be an export cipher and is either a SSLv2 or SSLv3/TLSv1 cipher (here TLSv1 is equivalent to SSLv3). To specify which ciphers to use, one can either specify all the Ciphers, one at a time, or use aliases to specify the preference and order for the ciphers.
kRSA
: RSA key exchangekDHr
: Diffie-Hellman key exchange with RSA keykDHd
: Diffie-Hellman key exchange with DSA keykEDH
: Ephemeral (temp.key) Diffie-Hellman key exchange (no cert)aNULL
: No authenticationaRSA
: RSA authenticationaDSS
: DSS authenticationaDH
: Diffie-Hellman authenticationeNULL
: No encodingDES
: DES encoding3DES
: Triple-DES encodingRC4
: RC4 encodingRC2
: RC2 encodingIDEA
: IDEA encodingMD5
: MD5 hash functionSHA1
: SHA1 hash functionSHA
: SHA hash functionSSLv2
: all SSL version 2.0 ciphersSSLv3
: all SSL version 3.0 ciphersTLSv1
: all TLS version 1.0 ciphersEXP
: all export ciphersEXPORT40
: all 40-bit export ciphers onlyEXPORT56
: all 56-bit export ciphers onlyLOW
: all low strength ciphers (no export, single DES)MEDIUM
: all ciphers with 128 bit encryptionHIGH
: all ciphers using Triple-DESRSA
: all ciphers using RSA key exchangeDH
: all ciphers using Diffie-Hellman key exchangeEDH
: all ciphers using Ephemeral Diffie-Hellman key exchangeADH
: all ciphers using Anonymous Diffie-Hellman key exchangeDSS
: all ciphers using DSS authenticationNULL
: all ciphers using no encryptionNow where this becomes interesting is that these can be put together to specify the order and ciphers you wish to use. To speed this up there are also aliases (SSLv2, SSLv3, TLSv1, EXP, LOW, MEDIUM, HIGH) for certain groups of ciphers. These tags can be joined together with prefixes to form the cipher-spec.
none
: add cipher to list+
: add ciphers to list and pull them to current location in list-
: remove cipher from list (can be added later again)!
: kill cipher from list completely (can not be added later again)openssl ciphers -v
command which provides a nice way to successively create the correct cipher-spec string. The default cipher-spec string is ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP
which means the following: first, remove from consideration any ciphers that do not authenticate, i.e. for SSL only the Anonymous Diffie-Hellman ciphers.
Next, use ciphers using RC4 and RSA. Next include the high, medium and then the low security ciphers.
Finally pull all SSLv2 and export ciphers to the end of the list.
$ openssl ciphers -v 'ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP' NULL-SHA SSLv3 Kx=RSA Au=RSA Enc=None Mac=SHA1 NULL-MD5 SSLv3 Kx=RSA Au=RSA Enc=None Mac=MD5 EDH-RSA-DES-CBC3-SHA SSLv3 Kx=DH Au=RSA Enc=3DES(168) Mac=SHA1 EXP-RC4-MD5 SSLv3 Kx=RSA(512) Au=RSA Enc=RC4(40) Mac=MD5 export EXP-RC2-CBC-MD5 SSLv2 Kx=RSA(512) Au=RSA Enc=RC2(40) Mac=MD5 export EXP-RC4-MD5 SSLv2 Kx=RSA(512) Au=RSA Enc=RC4(40) Mac=MD5 export
SSLCipherSuite RSA:!EXP:!NULL:+HIGH:+MEDIUM:-LOW