Last active
May 21, 2016 17:46
-
-
Save bradyvercher/2563100 to your computer and use it in GitHub Desktop.
Basic URL signing functions for WordPress
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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