Skip to content

Instantly share code, notes, and snippets.

@bradyvercher
Last active May 21, 2016 17:46
Show Gist options
  • Save bradyvercher/2563100 to your computer and use it in GitHub Desktop.
Save bradyvercher/2563100 to your computer and use it in GitHub Desktop.
Basic URL signing functions for WordPress
<?php
/**
* Basic URL Signing functions for WordPress.
*
* @author Brady Vercher (twitter.com/bradyvercher)
* @link http://www.blazersix.com/blog/protect-your-products-and-improve-your-systems-with-signed-urls/
*/
/**
* Sign a URL to ensure it hasn't been tampered with.
*
* @param string $url The URL to sign.
* @param array $args Optional. List of query args to add to the URL before signing.
* @return string Signed URL.
*/
function blazersix_sign_url( $url, $args = array() ) {
$args['token'] = false; // Remove a token if present.
$url = add_query_arg( $args, $url );
$token = blazersix_get_url_token( $url );
$url = add_query_arg( 'token', $token, $url );
return $url;
}
/**
* Generate a token for a given URL.
*
* An 'o' query parameter on a URL can include optional variables to test
* against when verifying a token without passing those variables around in
* the URL. For example, downloads can be limited to the IP that the URL was
* generated for by adding 'o=ip' to the query string.
*
* Or suppose when WordPress requested a URL for automatic updates, the user
* agent could be tested to ensure the URL is only valid for requests from
* that user agent.
*
* @param string $url The URL to generate a token for.
* @return string The token for the URL.
*/
function blazersix_get_url_token( $url ) {
$args = array();
// Add additional args to the URL for generating the token.
// Allows for restricting access to IP and/or user agent.
$parts = parse_url( $url );
$options = array();
if ( isset( $parts['query'] ) ) {
wp_parse_str( $parts['query'], $query_args );
// o = option checks (ip, user agent).
if ( ! empty( $query_args['o'] ) ) {
// Multiple options can be checked by separating them with a colon in the query parameter.
$options = explode( ':', rawurldecode( $query_args['o'] ) );
if ( in_array( 'ip', $options ) ) {
$args['ip'] = $_SERVER['REMOTE_ADDR'];
}
if ( in_array( 'ua', $options ) ) {
$args['user_agent'] = rawurlencode( $_SERVER['HTTP_USER_AGENT'] );
}
}
}
// Filter to modify arguments and allow custom options to be tested.
// Be sure to rawurlencode any custom options for consistent results.
$args = apply_filters( 'blazersix_get_url_token_args', $args, $url, $options );
$args['token'] = false; // Removes a token if present.
$parts = parse_url( add_query_arg( $args, $url ) );
$uri = $parts['path'];
$uri .= ( empty( $parts['query'] ) ) ? '' : '?' . $parts['query'];
$secret = apply_filters( 'blazersix_get_url_token_secret', wp_salt() );
$token = hash_hmac( 'md5', $uri, $secret );
return $token;
}
/**
* Generate a token for a URL and match it against the existing token to make
* sure the URL hasn't been tampered with.
*
* @param string $url URL to test.
* @return bool
*/
function blazersix_is_token_valid( $url ) {
$parts = parse_url( $url );
if ( isset( $parts['query'] ) ) {
wp_parse_str( $parts['query'], $query_args );
if ( isset( $query_args['token'] ) && $query_args['token'] == blazersix_get_url_token( $url ) ) {
return true;
}
}
return false;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment