Posts Tagged ‘security’

Downloading a Server’s HTTPS Certificate with Groovy

Posted in Code on August 2nd, 2012 by ataylor284 – 1 Comment

If you ever need to access a web service with HTTPS as a client in Java or groovy, and the service uses a self-signed certificate, you might need to import the SSL certificate into your local keystore.

To import the certificate, first you need to get it from the remote web server. Here’s a convenient little groovy script that downloads the certificate as a X509Certificate.

import javax.net.ssl.*

if (args.size() != 2) {
    println "usage: getCert host port"
}
def (host, port) = args
def cert
def trustManager = [
    checkClientTrusted: { chain, authType ->  },
    checkServerTrusted: { chain, authType -> cert = chain[0] },
    getAcceptedIssuers: { null }
] as X509TrustManager

def context = SSLContext.getInstance("TLS")
context.init(null, [trustManager] as TrustManager[], null)
context.socketFactory.createSocket(host, port as int).with {
    startHandshake()
    close()
}
println "-----BEGIN CERTIFICATE-----"
println cert.encoded.encodeBase64(true)
println "-----END CERTIFICATE-----"

This program prints out the certificate in a format that can be fed to keytool like so:

# get the certificate from the remote server
groovy getCert testserver 443 > certificate.txt
# print out the certificate details in a readable format
keytool -printcert -file certificate.txt
# import the certificate into the local keystore
keytool -import -file certificate.txt -alias testserver -keystore $JAVA_HOME/jre/lib/security/cacerts

Encrypting a Database Column in Grails

Posted in Code on December 14th, 2011 by ataylor284 – Comments Off on Encrypting a Database Column in Grails

Grails and hibernate user types make it easy to encrypt tables on a column by column basis.

Note that this approach has some limitations. Most importantly, you won’t be able to make queries based on the encrypted field, since they’ll try to match against the encrypted text instead of the plaintext.

The grails mapping DSL allows the user type to be specified easily:

    import ca.redtoad.crypto.hibernate.EncryptedString

    ...
        static mapping = {
            ccNumber type: EncryptedString
        }

Here’s the implementation of the user type. It stores the encrypted value as a JSON map containing the base64 encoded encrypted value and the salt. A text-based JSON representation is purely for convenience — it could easily be stored in binary form in a BLOB column to save space and parsing overhead.

package ca.redtoad.crypto.hibernate

import java.sql.*
import org.codehaus.groovy.grails.commons.ApplicationHolder
import org.hibernate.*
import org.hibernate.usertype.UserType
import grails.converters.JSON
import java.security.MessageDigest
import javax.crypto.*
import javax.crypto.spec.*

class EncryptedString implements UserType {

    int[] sqlTypes() { [Types.VARCHAR] as int[] }
    Class returnedClass() { String }
    boolean equals(x, y) { x == y }
    int hashCode(x) { x.hashCode() }
    Object deepCopy(value) { value }
    boolean isMutable() { false }
    Serializable disassemble(value) { value }
    def assemble(Serializable cached, owner) { cached }
    def replace(original, target, owner) { original }

    Object nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws HibernateException, SQLException {
        String str = resultSet.getString(names[0])
        str ? decrypt(str) : null
    }

    void nullSafeSet(PreparedStatement statement, Object value, int index) {
        statement.setString(index, value ? encrypt(value) : null)
    }
    private String encrypt(String plaintext) {
        String salt = 'Salt!'
        String key = "myKey"
        Cipher c = Cipher.getInstance('AES')
        byte[] keyBytes = MessageDigest.getInstance('SHA-1').digest("$salt$key".getBytes())[0..<16]
        c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, 'AES'))
        [data: c.doFinal(plaintext.bytes).encodeBase64() as String, salt: salt] as JSON
    }

    private String decrypt(String ciphertext) {
        def json = JSON.parse(ciphertext)
        Cipher c = Cipher.getInstance('AES')
        String key = "myKey"
        byte[] keyBytes = MessageDigest.getInstance('SHA-1').digest("${json.salt}${key}".getBytes())[0..<16]
        c.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBytes, 'AES'))
        new String(c.doFinal(json['data'].decodeBase64()))
    }
}

Logging Spring Security Events in Grails

Posted in Code on May 12th, 2011 by ataylor284 – 1 Comment

The grails spring-security-core plugin is great way to get full featured authentication in a web application with minimal effort. It mostly just works out of the box, and in combination with the spring-security-ui plugin, you can have fully functional login, self-registration (with email confirmation), and administration console with almost no code.

The underlying spring security library uses spring application events to inform the app when interesting stuff happens.

It’s sometimes nice to keep track of when users login — or fail to — and logout. A grails app can hook into spring security events by creating an ApplicationListener class in src/groovy.

Note that spring security doesn’t send events for logouts. Those can be captured by setting up a custom logout handler. Keep in mind you’ll only get logout events if the user logs out directly, rather than the session expiring.

This example handles both regular security events and logouts by logging them.

package ca.redtoad.security

import javax.servlet.http.*
import org.apache.commons.logging.LogFactory
import org.springframework.context.ApplicationListener
import org.springframework.security.authentication.event.AbstractAuthenticationEvent
import org.springframework.security.core.Authentication
import org.springframework.security.web.authentication.logout.LogoutHandler

class LoggingSecurityEventListener implements 
    ApplicationListener<AbstractAuthenticationEvent>, LogoutHandler {

    private static final log = LogFactory.getLog(this)

    void onApplicationEvent(AbstractAuthenticationEvent event) {
        event.authentication.with {
            def username = principal.hasProperty('username')?.getProperty(principal) ?: principal
            log.info "event=${event.class.simpleName} username=${username} " +
                "remoteAddress=${details.remoteAddress} sessionId=${details.sessionId}"
        }
    }

    void logout(HttpServletRequest request, HttpServletResponse response, 
        Authentication authentication) {
        authentication.with {
            def username = principal.hasProperty('username')?.getProperty(principal) ?: principal
            log.info "event=Logout username=${username} " +
                "remoteAddress=${details.remoteAddress} sessionId=${details.sessionId}"
        }
    }
}

Next the security event listener has to be registered as a spring bean in grails-app/conf/spring/resources.groovy.

import ca.redtoad.security.LoggingSecurityEventListener

beans = {
    securityEventListener(LoggingSecurityEventListener)
}

Finally, we need make two additions to grails-app/conf/Config.groovy: turn on the grails security event listener, and override the logout handlers to include ours.

grails.plugins.springsecurity.useSecurityEventListener = true
grails.plugins.springsecurity.logout.handlerNames = 
    ['rememberMeServices',
     'securityContextLogoutHandler', 
     'securityEventListener']

Cross Site Request Forgeries (CSRF) and Grails

Posted in Code on January 26th, 2011 by ataylor284 – 6 Comments

I recently had to come up with defenses against cross-site request forgery (CSRF) attacks for a grails application. This goes along with hand-in-hand with XSS injection protection to make your site as secure as possible. There’s lots of information spread out on the internet about CSRFs, but nothing specifically for grails, so here’s a quick guide I whipped up.

Require POST

Forms that change state should be submitted with POSTs. In views, g:forms should use the post method. This is the default for g:form tags, but regular form tags default to GET, so I prefer to make it explicit.

In controllers, limit the accepted methods for your actions with a static allowedMethods block. If the form gets submitted with a get, grails will return a 405 error code to the browser.

class SomethingController {
    static allowedMethods = [save: 'POST', update: 'POST',
        delete: 'POST']

    ...

}

Use A Form Token

Use the one-time token grails provides. This prevents accidental double submits, but it also rejects forged requests that weren’t submitted from your form page. A unique token is generated when the form gets loaded, and if it’s wrong or not present when the form get submitted, the controller can return an error.

<g:form action="save" method="post" useToken="true">

Wrap your controller in a withForm block:

class SomethingController {
    ...

    def save = {
        withForm {
            // token was correct, save the object
        }.invalidToken {
            response.status = 405
        }
    }
}

Verify the referer

The referer HTTP header will be set to form that submitted your request. This should be from your application, and it’s easy to test it and ensure it really is. No need for this on GET requests though, since it’ll break bookmarks and deep links in. This can be enforced on POSTs with a simple filter in grails-app/conf:

import org.codehaus.groovy.grails.commons.ConfigurationHolder as CH

class RefererFilters {
    // referer must match serverURL, optionally https
    static validRefererPrefix = "^${CH.config.grails.serverURL}".replace("http", "https?")
    def filters = {
        checkReferer(controller: '*', action: '*') {
            before = {
                if (request.method.toUpperCase() == "POST") {
                    def referer = request.getHeader('Referer')

                    return referer && referer =~ validRefererPrefix
                }
            }
        }
    }
}

(Maybe) Adjust the session timeout

The default session duration for tomcat is 30 minutes. A lower value can close the time window for CSRFs, but can also harm the usability of the site. To customize it, run grails install-templates add this to src/templates/war/web.xml inside the web-app tag:

<session-config>
   <session-timeout>60</session-timeout>
</session-config>

References: