blob: c7e397845dbc34af92375f09880a0b8deb1ee79f [file] [log] [blame]
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