{"id":361,"date":"2013-02-01T10:49:19","date_gmt":"2013-02-01T10:49:19","guid":{"rendered":"http:\/\/nicholshayes.co.uk\/blog\/?p=361"},"modified":"2013-10-31T15:56:11","modified_gmt":"2013-10-31T15:56:11","slug":"securing-your-api-keys","status":"publish","type":"post","link":"http:\/\/nicholshayes.co.uk\/blog\/?p=361","title":{"rendered":"Securing your api keys"},"content":{"rendered":"<p>A Rails app often has to connect to other services via an api key. For example, if you want users to be able to log in via their google credentials. One problem this raises is how to secure these api keys.<\/p>\n<p>The solution I&#8217;ve used in my latest app, was to encrypt the key in the database. With this solution, the key is:<\/p>\n<ul>\n<li>instance specific;<\/li>\n<li>can be made easy to access through the app, but difficult out side the app;<\/li>\n<li>is not stored in the app code;<\/li>\n<li>doesn&#8217;t rely on having to load extra files to production environments.<\/li>\n<\/ul>\n<p>I decided to base my solution on a <a title=\"SelfAssessment Setting\" href=\"https:\/\/github.com\/reggieb\/SelfAssessment\/blob\/99809253dc05feb89fb49af69def691db2a8040d\/app\/models\/setting.rb\">Setting model I had used in another app<\/a>. This would give me a way of storing the setting data, and retrieving it.<\/p>\n<p>However, each setting value is stored in plain text in the database, so the setting would not only be accessible via the app, but also directly from the database.\u00a0<strong>The value needed to be encrypted. <\/strong>I decided that I would not want to encrypt all settings, so I wanted encryption to be an optional setting.<\/p>\n<p>The end result was <a title=\"Mournful settings on git hub\" href=\"https:\/\/github.com\/reggieb\/mournful_settings\">mournful settings<\/a>.<\/p>\n<p>With this in place I was able to store my api keys and secrets encrypted in the database and retrieve them like this (example from devise initializer):<\/p>\n<div class=\"codecolorer-container ruby default\" style=\"overflow:auto;white-space:nowrap;\"><div class=\"ruby codecolorer\">config.<span class=\"me1\">omniauth<\/span><span class=\"br0\">&#40;<\/span><br \/>\n&nbsp; <span class=\"re3\">:google_oauth2<\/span>,<br \/>\n&nbsp; Setting.<span class=\"kw1\">for<\/span><span class=\"br0\">&#40;<\/span><span class=\"re3\">:google_client_id<\/span><span class=\"br0\">&#41;<\/span>, <br \/>\n&nbsp; Setting.<span class=\"kw1\">for<\/span><span class=\"br0\">&#40;<\/span><span class=\"re3\">:google_client_secret<\/span><span class=\"br0\">&#41;<\/span> &nbsp;<br \/>\n<span class=\"br0\">&#41;<\/span><\/div><\/div>\n<p>I used seeding to set up the setting objects with invalid values, and exposed the setting model via <a href=\"http:\/\/activeadmin.info\/\">active_admin<\/a> with this register:<\/p>\n<div class=\"codecolorer-container ruby default\" style=\"overflow:auto;white-space:nowrap;height:300px;\"><div class=\"ruby codecolorer\">ActiveAdmin.<span class=\"me1\">register<\/span> Setting <span class=\"kw1\">do<\/span><br \/>\n&nbsp; <br \/>\n&nbsp; actions <span class=\"re3\">:all<\/span>, <span class=\"re3\">:except<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">&#91;<\/span><span class=\"re3\">:destroy<\/span><span class=\"br0\">&#93;<\/span><br \/>\n&nbsp; <br \/>\n&nbsp; index <span class=\"kw1\">do<\/span><br \/>\n&nbsp; &nbsp; selectable_column<br \/>\n&nbsp; &nbsp; column <span class=\"re3\">:name<\/span><br \/>\n&nbsp; &nbsp; column <span class=\"re3\">:description<\/span><br \/>\n&nbsp; &nbsp; column <span class=\"re3\">:value<\/span><br \/>\n&nbsp; &nbsp; column <span class=\"re3\">:encrypted<\/span><br \/>\n&nbsp; &nbsp; default_actions<br \/>\n&nbsp; <span class=\"kw1\">end<\/span><br \/>\n&nbsp; <br \/>\n&nbsp; form <span class=\"kw1\">do<\/span> <span class=\"sy0\">|<\/span>f<span class=\"sy0\">|<\/span><br \/>\n&nbsp; &nbsp; f.<span class=\"me1\">inputs<\/span> <span class=\"st0\">&quot;Details&quot;<\/span> <span class=\"kw1\">do<\/span><br \/>\n&nbsp; &nbsp; &nbsp; f.<span class=\"me1\">input<\/span> <span class=\"re3\">:name<\/span><br \/>\n&nbsp; &nbsp; &nbsp; f.<span class=\"me1\">input<\/span> <span class=\"re3\">:description<\/span><br \/>\n&nbsp; &nbsp; &nbsp; f.<span class=\"me1\">input<\/span> <span class=\"re3\">:value<\/span>, <span class=\"re3\">:input_html<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">&#123;<\/span>:value <span class=\"sy0\">=&gt;<\/span> setting.<span class=\"me1\">value<\/span><span class=\"br0\">&#125;<\/span><br \/>\n&nbsp; &nbsp; &nbsp; f.<span class=\"me1\">input<\/span> <span class=\"re3\">:encrypted<\/span><br \/>\n&nbsp; &nbsp; <span class=\"kw1\">end<\/span><br \/>\n&nbsp; &nbsp; f.<span class=\"me1\">buttons<\/span><br \/>\n&nbsp; <span class=\"kw1\">end<\/span><br \/>\n&nbsp; <br \/>\n<span class=\"kw1\">end<\/span><\/div><\/div>\n<p>In this way api keys can be accessed via administrators and modified as needed. <\/p>\n<p>Of course, this is only as secure as the active admin interface, but that&#8217;s fine for this project. If I was being paranoid, I&#8217;d not expose the setting model via a web interface, and instead create and edit settings via the console.<\/p>\n<p><strong>An update<\/strong><br \/>\nRecently I needed to secure some api keys without putting them into the database, and I used <a href=\"https:\/\/github.com\/laserlemon\/figaro\">figaro<\/a>. Definitely worth a look at if you need to secure api keys without having to exposed them via an admin interface.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A Rails app often has to connect to other services via an api key. For example, if you want users to be able to log in via their google credentials. One problem this raises is how to secure these api &hellip; <a href=\"http:\/\/nicholshayes.co.uk\/blog\/?p=361\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[3],"tags":[],"_links":{"self":[{"href":"http:\/\/nicholshayes.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/361"}],"collection":[{"href":"http:\/\/nicholshayes.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/nicholshayes.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/nicholshayes.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"http:\/\/nicholshayes.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=361"}],"version-history":[{"count":12,"href":"http:\/\/nicholshayes.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/361\/revisions"}],"predecessor-version":[{"id":458,"href":"http:\/\/nicholshayes.co.uk\/blog\/index.php?rest_route=\/wp\/v2\/posts\/361\/revisions\/458"}],"wp:attachment":[{"href":"http:\/\/nicholshayes.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=361"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/nicholshayes.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=361"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/nicholshayes.co.uk\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=361"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}