| Signed URL plugin |
| |
| This ATS plugin checks a signature query string on the URL, and rejects (HTTP |
| 403), or redirects (HTTP 302) when this check fails. The signature is based on |
| a secret (key) that a signing portal and the Traffic Server cache share. The |
| algorithm for the signature can be MD5 or SHA1. When the check passes, the |
| query string is stripped, and the request is handled as if there was no query |
| string in the first place. |
| |
| This plugin comes with 2 example perl scripts. The sign.pl script shows how to |
| sign a URL using the different options, this script is just an example, in any |
| real usage scenario, the content owner will incorporate this functionality in |
| their portal. The genkeys.pl script is a quick hack to generate a config file |
| with random keys. Keep your keys to yourself (secret) if you are using this |
| plugin, and only share them with the content owner. |
| |
| Signed URLs do not replace DRM. |
| |
| Quick install: |
| You can build with ./configure --enable-experimental-plugins or |
| with tsxs: |
| |
| Make sure devel packages for traffic-server are installed. |
| Make sure that 'tsxs' is in your path. |
| Make sure versions of this plugin and ATS are compatible. |
| |
| make -f Makefile.tsxs |
| make -f Makefile.tsxs install |
| |
| add @plugin=url_sig.so @pparam=<config file> to the remap rule you want |
| to be signed |
| |
| |
| Edge cache debugging |
| To enable the TSDebug verbose logging, change records.config to have: |
| |
| CONFIG proxy.config.diags.debug.enabled INT 1 |
| CONFIG proxy.config.diags.debug.tags STRING url_sig |
| |
| and do a traffic_ctl config reload; Debug output will go to traffic.out. |
| Failed transactions (signature check fails that is) will be logged |
| in to error.log. |
| |
| Signing a URL |
| At the signing portal take the full URL, without any query string, and |
| add on a query string with the following parameters: |
| |
| Client IP address |
| The client IP address that this signature is valid for. |
| C=<client IP address> |
| Expiration |
| The Expiration time (seconds since epoch) of this signature. |
| E=<expiration time in secs since unix epoch> |
| Algorithm |
| The Algorithm used to create the signature. Only 1 (HMAC_SHA1) |
| and 2 (HMAC_MD5) are supported at this time |
| A=<algorithm number> |
| Key index |
| Index of the key used. This is the index of the key in the |
| configuration file on the cache. The set of keys is a shared |
| secret between the signing portal and the edge caches. There |
| is one set of keys per reverse proxy domain (fqdn). |
| K=<key index used> |
| Parts |
| Parts to use for the signature, always excluding the scheme |
| (http://). parts0 = fqdn, parts1..x is the directory parts |
| of the path, if there are more parts to the path than letters |
| in the parts param, the last one is repeated for those. |
| Examples: |
| 1: use fqdn and all of URl path |
| 0110: use part1 and part 2 of path only |
| 01: use everything except the fqdn |
| P=<parts string (0's and 1's> |
| Signature |
| The signature over the parts + the query string up to and |
| including "S=". |
| S=<signature> |
| |
| Signing a URL using path parameters instead of using a query string. |
| |
| The parameters above may be embedded in the path part of the request |
| url vs using a query string. When this method is used, the parameters |
| above are inserted after the path but before the file part of the path |
| in the request url. Any origin application query parameters then follow |
| the file part of the request and are never part of the sign string. |
| |
| Path parameters are separated by a ';' in the path. The complete signature |
| string is base64 encoded as a single path parameter that is assigned to the |
| 'siganchor', and will appear in that path as siganchor=base64string. The |
| following is an example signed request using the path parameter method and |
| with an origin application query string: |
| |
| http://ds-01.comcast.net/vod/t;urlsig=O0U9MTQ2MzkyOTYxODtBPTE7Sz0zO1A9MTtTPTEyZDlmN2RiNjUyZWI0YmI4MWYyNmVlMjE3MzczZGE5Y2VkYTRmZGY/Frag10Num10.ts?appid=2&t=1 |
| |
| Note that the signing string is embedded in the path between the last |
| directory part and before the file part of the request. Using 'parts' in |
| sign.pl, the signature may be signed accordingly up to S= in the above |
| request. To generate a signed url using this method, use the --pathparams |
| option in sign.pl |
| |
| |
| |
| |
| |
| Example |
| Build, install |
| |
| make -f Makefile.tsxs |
| make -f Makefile.tsxs install |
| |
| Create the config file, using the genkeys script, or otherwise. |
| |
| $ ./genkeys.pl > /usr/local/trafficserver-master/etc/trafficserver/sign_test.config |
| $ cat /usr/local/trafficserver-master/etc/trafficserver/sign_test.config |
| key0 = YwG7iAxDo6Gaa38KJOceV4nsxiAJZ3DS |
| key1 = nLE3SZKRgaNM9hLz_HnIvrCw_GtTUJT1 |
| key2 = YicZbmr6KlxfxPTJ3p9vYhARdPQ9WJYZ |
| key3 = DTV4Tcn046eM9BzJMeYrYpm3kbqOtBs7 |
| key4 = C1r6R6MINoQd5YSH25fU66tuRhhz3fs_ |
| key5 = l4dxe6YEpYbJtyiOmX5mafhwKImC5kej |
| key6 = ekKNHXu9_oOC5eqIGJVxV0vI9FYvKVya |
| key7 = BrjibTmpTTuhMHqphkQAuCWA0Zg97WQB |
| key8 = rEtWLb1jcYoq9VG8Z8TKgX4GxBuro20J |
| key9 = mrP_6ibDBG4iYpfDB6W8yn3ZyGmdwc6M |
| key10 = tbzoTTGZXPLcvpswCQCYz1DAIZcAOGyX |
| key11 = lWsn6gUeSEW79Fk2kwKVfzhVG87EXLna |
| key12 = Riox0SmGtBWsrieLUHVWtpj18STM4MP1 |
| key13 = kBsn332B7yG3HdcV7Tw51pkvHod7_84l |
| key14 = hYI4GUoIlZRf0AyuXkT3QLvBMEoFxkma |
| key15 = EIgJKwIR0LU9CUeTUdVtjMgGmxeCIbdg |
| error_url = 403 |
| $ |
| |
| Add the remap rule like |
| |
| map http://test-remap.domain.com http://google.com @plugin=url_sig.so @pparam=sign_test.config @pparam=pristineurl |
| |
| Restart traffic server or traffic_ctl config reload - verify there are no errors in diags.log |
| |
| Try the path unsigned: |
| |
| $ curl -vs -H'Host: test-remap.domain.com' http://localhost:8080/ |
| * Adding handle: conn: 0x200f8a0 |
| * Adding handle: send: 0 |
| * Adding handle: recv: 0 |
| * Curl_addHandleToPipeline: length: 1 |
| * - Conn 0 (0x200f8a0) send_pipe: 1, recv_pipe: 0 |
| * About to connect() to localhost port 8080 (#0) |
| * Trying 127.0.0.1... |
| * Connected to localhost (127.0.0.1) port 8080 (#0) |
| > GET / HTTP/1.1 |
| > User-Agent: curl/7.32.0 |
| > Accept: */* |
| > Host: test-remap.domain.com |
| > |
| < HTTP/1.1 403 Forbidden |
| < Date: Tue, 15 Apr 2014 22:57:32 GMT |
| < Connection: close |
| * Server ATS/5.0.0 is not blacklisted |
| < Server: ATS/5.0.0 |
| < Cache-Control: no-store |
| < Content-Type: text/plain |
| < Content-Language: en |
| < Content-Length: 21 |
| < |
| * Closing connection 0 |
| Authorization Denied$ |
| $ |
| |
| Sign the URL and try it again. Run the script with appropriate params, and |
| it will output the curl line to run: |
| |
| $ ./sign.pl --url http://test-remap.domain.com/ --useparts 1 --algorithm 1 --duration 60 --keyindex 3 --key DTV4Tcn046eM9BzJMeYrYpm3kbqOtBs7 |
| curl -s -o /dev/null -v --max-redirs 0 'http://test-remap.domain.com/?E=1397603088&A=1&K=3&P=1&S=28d822f68ac7265db61a8441e0877a98fe1007cc' |
| |
| Since test-remap.domain.com doesn't actually exist, we have to change that line slightly: |
| |
| $ curl -s -o /dev/null -v --max-redirs 0 -H 'Host: test-remap.domain.com' 'http://localhost:8080/?E=1397603088&A=1&K=3&P=1&S=28d822f68ac7265db61a8441e0877a98fe1007cc' |
| * Adding handle: conn: 0xef0a90 |
| * Adding handle: send: 0 |
| * Adding handle: recv: 0 |
| * Curl_addHandleToPipeline: length: 1 |
| * - Conn 0 (0xef0a90) send_pipe: 1, recv_pipe: 0 |
| * About to connect() to localhost port 8080 (#0) |
| * Trying 127.0.0.1... |
| * Connected to localhost (127.0.0.1) port 8080 (#0) |
| > GET /?E=1397603088&A=1&K=3&P=1&S=28d822f68ac7265db61a8441e0877a98fe1007cc HTTP/1.1 |
| > User-Agent: curl/7.32.0 |
| > Accept: */* |
| > Host: test-remap.domain.com |
| > |
| < HTTP/1.1 200 OK |
| < Location: http://www.google.com/ |
| < Content-Type: text/html; charset=UTF-8 |
| < Date: Tue, 15 Apr 2014 23:04:36 GMT |
| < Expires: Thu, 15 May 2014 23:04:36 GMT |
| < Cache-Control: public, max-age=2592000 |
| * Server ATS/5.0.0 is not blacklisted |
| < Server: ATS/5.0.0 |
| < Content-Length: 219 |
| < X-XSS-Protection: 1; mode=block |
| < X-Frame-Options: SAMEORIGIN |
| < Alternate-Protocol: 80:quic |
| < Age: 0 |
| < Connection: keep-alive |
| < |
| { [data not shown] |
| * Connection #0 to host localhost left intact |
| $ |
| |
| Generating a signed URL with path parameters: |
| |
| $ ./sign.pl --url "http://test-remap.domain.com/vod/t/prog_index.m3u8?appid=2&t=1" --useparts 1 --algorithm 1 --duration 86400 --keyindex 3 --key kSCE1_uBREdGI3TPnr_dXKc9f_J4ZV2f --pathparams --siganchor urlsig |
| |
| curl -s -o /dev/null -v --max-redirs 0 'http://test-remap.domain.com/vod/t;urlsig=O0U9MTQ2MzkyOTM4NTtBPTE7Sz0zO1A9MTtTPTIxYzk2YWRiZWZkOGJkMDFhYmM3MmZkMTEzMWVkMGM5ZmU1ZmFiMjE/prog_index.m3u8?appid=2&t=1' |
| |
| |
| Client IP in the Signing Script |
| Below is an example of how to include client ip in the signing script |
| Works for both IPv4 and IPv6 |
| --client 10.10.10.10 |