PageRenderTime 44ms CodeModel.GetById 37ms app.highlight 4ms RepoModel.GetById 1ms app.codeStats 0ms

/blog/2012/12/17/http-signatures-with-content-hmac/index.html

https://github.com/progrium/progrium.github.com
HTML | 146 lines | 105 code | 40 blank | 1 comment | 0 complexity | 103c7dbc73c46d20530146b30b846f72 MD5 | raw file
  1<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  2        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  3<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  4  <head>
  5    <title>HTTP Signatures with Content-HMAC :: Jeff Lindsay
  6      </title>
  7
  8    
  9    <meta name="description" content="" />
 10    
 11    <meta name="author" content="Jeff Lindsay" />
 12
 13    <script type="text/javascript" src="/scripts/jquery-1.7.2.min.js"></script>
 14
 15    <link href="http://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet" type="text/css" />
 16    <link href="http://fonts.googleapis.com/css?family=VT323" rel="stylesheet" type="text/css" />
 17
 18
 19    <link rel="stylesheet" type="text/css" href="/style/bootstrap.min.css" />
 20    <link rel="stylesheet" type="text/css" href="/style/pager.min.css" />
 21    <link rel="stylesheet" type="text/css" href="/style/alerts.min.css" />
 22    <link rel="stylesheet/less" type="text/css" href="/style/progrium.less" />
 23
 24    <link rel="shortcut icon" type="image/x-icon" href="/images/JeffLindsayDeluxe.png" />
 25
 26    <script type="text/javascript" src="/scripts/less-1.3.0.min.js"></script>
 27
 28    <link rel="me" href="http://www.google.com/profiles/progrium" />
 29    <link rel="alternate" type="application/atom+xml" href="/blog/atom.xml" title="Jeff's Blog" />
 30  </head>
 31  <body>
 32    <div id="header">
 33      <div class="container">
 34        <div id="tree"></div>
 35        <h2><a href="/" title="Pragmatic idealist. Builder. Thought explorer."><span>Jeff Li</span>nds<span>ay</span></a></h2>
 36        <ul>
 37          <li><a href="/blog">Blog</a></li>
 38          <li><a href="http://github.com/progrium">Projects</a></li>
 39          <!--li>Blueprints</li-->
 40          <li><a href="/about.html">About</a></li>
 41          <li id="hire"><a href="mailto:progrium+hire@gmail.com">Hire Me</a></li>
 42        </ul>
 43      </div>
 44    </div>
 45    <div id="content">
 46      <div class="container">
 47        <div class="sidebar">
 48  <div class="portrait">
 49    <img src="/images/JeffLindsayDeluxe.png" width="150" height="150" />
 50  </div>
 51  <div class="button"><a href="/blog/atom.xml">Subscribe to Blog</a></div>
 52  <h6>Related Posts</h6>
 53  <ul>
 54    
 55    <li><a href="/blog/2014/02/06/the-start-of-the-age-of-flynn">The Start of the Age of Flynn</a></li>
 56    
 57    <li><a href="/blog/2013/11/13/viewdocs-hosted-markdown-project-documentation">Viewdocs: Hosted Markdown project documentation (finally!)</a></li>
 58    
 59    <li><a href="/blog/2013/08/18/hacker-dojo-community-trading-zone">Hacker Dojo: Community Trading Zone</a></li>
 60    
 61    <li><a href="/blog/2013/06/19/dokku-the-smallest-paas-implementation-youve-ever-seen">Dokku: The smallest PaaS implementation you've ever seen</a></li>
 62    
 63    <li><a href="/blog/2013/01/05/executable-tweets-and-programs-in-short-urls">Executable Tweets and Programs in Short URLs</a></li>
 64    
 65    <li><a href="/blog/2013/01/01/where-did-localtunnel-come-from">Where did Localtunnel come from?</a></li>
 66    
 67    <li><a href="/blog/2012/12/25/localtunnel-v2-available-in-beta">Localtunnel v2 available in beta</a></li>
 68    
 69    <li><a href="/blog/2012/12/15/avoiding-environmental-fallacy-with-systems-thinking">Avoiding environmental fallacy with systems thinking</a></li>
 70    
 71    <li><a href="/blog/2012/12/06/async-http-responses-with-response-redirection">Async HTTP Responses with Response Redirection</a></li>
 72    
 73    <li><a href="/blog/2012/11/26/x-callback-header-an-evented-web-building-block">X-Callback Header: Evented Web Building Block</a></li>
 74    
 75  </ul>
 76</div>
 77
 78
 79
 80
 81<div class="article">
 82  <div class="date">
 83    <span class="month">Dec</span>
 84    <span class="day">17</span><br />
 85    <span class="year">2012</span>
 86  </div>
 87  <h1><a href="/blog/2012/12/17/http-signatures-with-content-hmac">HTTP Signatures with Content-HMAC</a></h1>
 88  <p>Today I wanted to propose another header. It would be used for signing HTTP content with HMAC, and is appropriately called Content-HMAC. In <a href='http://progrium.com/blog/2012/11/26/x-callback-header-an-evented-web-building-block/'>a previous post</a> about the Callback header, I mentioned using an X-Signature header in callback requests to sign the payload of the callback. It looked like this:</p>
 89
 90<pre><code>X-Signature: sha1=&lt;hexdigest of sha1 hmac&gt;</code></pre>
 91
 92<p>The HMAC would be built with just the content of the request (i.e., no headers, no query params) and a secret key. <a href='http://pubsubhubbub.googlecode.com/svn/trunk/pubsubhubbub-core-0.3.html#authednotify'>This was borrowed directly from the PubSubHubbub spec</a>, but the general idea of using HMAC to sign callback requests has become pretty standard in the world of webhooks. Here are details on how <a href='http://code.google.com/p/support/wiki/PostCommitWebHooks#Authentication'>Google</a> and <a href='http://www.twilio.com/docs/security#validating-requests'>Twilio</a> use them.</p>
 93
 94<p>Each of these providers is using their own header for basically the same use case. It would seem like there is an opportunity to standardize on a common header format for it. There&#8217;s been a number of proposals for a general Signature header to sign an entire request. There was a fairly comprehensive one proposed called <a href='http://tools.ietf.org/html/draft-burke-content-signature-00'>Content-Signature</a>. With signing, the difficulty is often getting the input string correct. Most signing mechanisms need to normalize their input. If you&#8217;ve ever had to deal with OAuth or AWS signatures, you&#8217;ll know what I&#8217;m talking about. With request signing, the headers pose a particularly tricky situation with signing since they often change as the request goes through proxies.</p>
 95
 96<p>The idea of Content-HMAC is to focus on a simpler goal of signing just the content payload, since it&#8217;s normally treated as-is, and is not altered when going through proxies. The X-Signature proposal I had was a decent one, as is almost any cowpath-based proposal, but I realized it would probably be a good idea to limit the implied scope to what it&#8217;s really doing: providing an HMAC for request (or response) content.</p>
 97
 98<p>It turns out there&#8217;s a similar header that&#8217;s not used that often anymore called Content-MD5. It was a simple mechanism to provide an MD5 digest of the content. My current proposal is to take this existing pattern and apply it to HMAC, giving us the Content-HMAC header:</p>
 99
100<pre><code>Content-HMAC: &lt;hash mechanism&gt; &lt;base64 encoded binary HMAC&gt;</code></pre>
101
102<p>Here&#8217;s an example:</p>
103
104<pre><code>Content-HMAC: sha1 f1wOnLLwcTexwCSRCNXEAKPDm+U=</code></pre>
105
106<p>This proposal borrows its naming convention from Content-MD5, but the format is more similar to Authorization. The Authorization header allows multiple authorization schemes to be used. You define the scheme followed by a space and then the actual authorization data. Since HMAC allows different hashing techniques to be used, we use that pattern here to let you specify the hashing technique. We also take the existing pattern of base64 encoding used in several HTTP headers to make it conform even more to existing standards.</p>
107
108<p>Content-HMAC was created for callback requests, but it&#8217;s a useful way to sign any HTTP request or response payload. For requests, it&#8217;s worth mentioning it only applies when there is a content payload, so for example it&#8217;s meaningless with GET requests.</p>
109
110<p>It&#8217;s also very worth mentioning that the need for content signing is unnecessary when using HTTPS. It currently looks like the future will eventually be 100% SSL encrypted HTTP, but until then, there will always be situations where HTTPS is not available. Content-HMAC is perhaps a stop-gap until we reach that ideal. Until then, I think Content-HMAC is a good, standard way to add authorization to callback requests.</p>
111
112<p>Let me know if you have any questions or feedback on this proposal. Further discussion is likely to happen on the <a href='https://groups.google.com/forum/#!forum/webhooks'>Webhooks Google Group</a>.</p>
113</div>
114
115<hr />
116 <div id="disqus_thread"></div>
117        <script type="text/javascript">
118            /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */
119            var disqus_shortname = 'progrium'; // required: replace example with your forum shortname
120
121            /* * * DON'T EDIT BELOW THIS LINE * * */
122            (function() {
123                var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
124                dsq.src = 'http://' + disqus_shortname + '.disqus.com/embed.js';
125                (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
126            })();
127        </script>
128        <noscript>Please enable JavaScript to view the <a href="http://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
129        <a href="http://disqus.com" class="dsq-brlink">comments powered by <span class="logo-disqus">Disqus</span></a>
130
131      </div>
132      <div id="roots">
133        <img src="/images/roots.png" />
134      </div>
135    </div>
136    <script type="text/javascript">
137        var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
138        document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
139        </script>
140        <script type="text/javascript">
141        try {
142        var pageTracker = _gat._getTracker("UA-6824126-1");
143        pageTracker._trackPageview();
144        } catch(err) {}</script>
145  </body>
146</html>