{"id":1995,"date":"2015-02-02T15:07:00","date_gmt":"2015-02-02T13:07:00","guid":{"rendered":"http:\/\/hasselba.ch\/blog\/?p=1995"},"modified":"2016-10-30T20:12:26","modified_gmt":"2016-10-30T18:12:26","slug":"rest-security-same-origin-policy-cors","status":"publish","type":"post","link":"https:\/\/hasselba.ch\/blog\/?p=1995","title":{"rendered":"REST &#038; Security: Same-Origin Policy \/ CORS"},"content":{"rendered":"<p>The &#8222;<a title=\"wikipedia.org: Same-origin policy\" href=\"http:\/\/en.wikipedia.org\/wiki\/Same-origin_policy\" target=\"_blank\"><em>Same-orginin policy<\/em>&#8222;<\/a> is an important concept for protecting web applications. In short, only resources from the same domain are allowed, everything else is <del>permitted<\/del> denied. To allow access other domains in your application, you have to enable <a title=\"wikipedia.org: Cross-origin resource sharing\" href=\"http:\/\/en.wikipedia.org\/wiki\/Cross-origin_resource_sharing\" target=\"_blank\">&#8222;<em>CORS<\/em>&#8222;<\/a>, a<a title=\"markbarton.com: Enabling CORS with Domino to allow Cross Domain Requests\" href=\"http:\/\/www.markbarton.com\/?p=344\" target=\"_blank\"> tutorial how to enable this on a Domino server<\/a> was written by Mark Barton a while ago.<\/p>\n<p>It works fine for protecting an applications against DOM manipulations and\/or injection of malicous script code, but this client side security restriction only blocks <span style=\"text-decoration: underline;\">the response<\/span> from the server. The client still <span style=\"text-decoration: underline;\">sends a request<\/span>, and this can be problematic for the security of a RESTful application.<\/p>\n<p>To clearify this, here is a short example:<\/p>\n<p>I have created a small HTML page containing an Ajax request to load some code of a XPages-based REST service on another server. This file is hosted on my hasselba.ch server, and wants to access some data on my local Domino server:<\/p>\n<pre><code>&lt;html&gt;\r\n\u00a0\u00a0 &lt;body&gt;\r\n\u00a0\u00a0 &lt;h1&gt;SOP Demo&lt;\/h1&gt;\r\n\u00a0\u00a0 &lt;script&gt;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 var xhr =(window.XMLHttpRequest)?new XMLHttpRequest():\r\n          new ActiveXObject(\"Microsoft.XMLHTTP\");\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 xhr.open(\"GET\",\"http:\/\/localhost\/REST.nsf\/SOPDemo.xsp\/foo\/\",true);\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 xhr.withCredentials = true;\r\n\u00a0\u00a0\u00a0\u00a0\u00a0 xhr.send();\r\n\u00a0\u00a0 &lt;\/script&gt;\r\n\r\n\u00a0\u00a0 &lt;\/body&gt;\r\n&lt;\/html&gt;<\/code><\/pre>\n<p>The &#8222;<em>withCredential<\/em>&#8220; options ensures that an eventually existing Domino session is used when performing the request.<\/p>\n<p>The REST service on my Domino server prints the actual username to the console:<\/p>\n<pre><code>&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\r\n&lt;xp:view\r\n\u00a0\u00a0 \u00a0xmlns:xp=\"http:\/\/www.ibm.com\/xsp\/core\"\r\n\u00a0\u00a0 \u00a0xmlns:xe=\"http:\/\/www.ibm.com\/xsp\/coreex\"\r\n\u00a0\u00a0 \u00a0rendered=\"false\"&gt;\r\n\u00a0\u00a0 \u00a0\r\n\u00a0\u00a0 \u00a0&lt;xe:restService\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0id=\"restService\"\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0pathInfo=\"foo\"&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;xe:this.service&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0&lt;xe:customRestService\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0requestContentType=\"application\/json\"\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0requestVar=\"data\"&gt;\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0 \r\n\u00a0\u00a0 \u00a0\u00a0\u00a0\u00a0         &lt;xp:this.doGet&gt;\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0       &lt;![CDATA[#{javascript:\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0      print(\"Hello '\" + session.getEffectiveUserName() + \"'\");\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0      \"{}\"\r\n\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0\u00a0\u00a0 \u00a0       }]]&gt;\r\n                &lt;\/xp:this.doGet&gt;\r\n\u00a0\u00a0 \u00a0         &lt;\/xe:customRestService&gt;\r\n         &lt;\/xe:this.service&gt;\r\n     &lt;\/xe:restService&gt;\r\n&lt;\/xp:view&gt;\r\n<\/code><\/pre>\n<p>When opening this page, the response of the request is blocked, and that&#8217;s what the &#8222;<em>Same-origin policy<\/em>&#8220; was made for: If the response contains malicious Javascript code, this script won&#8217;t get executed.<\/p>\n<p><a href=\"https:\/\/hasselba.ch\/blog\/wp-content\/uploads\/2015\/02\/01.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-1996\" src=\"https:\/\/hasselba.ch\/blog\/wp-content\/uploads\/2015\/02\/01-300x148.png\" alt=\"01\" width=\"300\" height=\"148\" srcset=\"https:\/\/hasselba.ch\/blog\/wp-content\/uploads\/2015\/02\/01-300x148.png 300w, https:\/\/hasselba.ch\/blog\/wp-content\/uploads\/2015\/02\/01.png 793w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>The client is protected, but what about the request send to the server?<\/p>\n<p><a href=\"https:\/\/hasselba.ch\/blog\/wp-content\/uploads\/2015\/02\/02.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-1997\" src=\"https:\/\/hasselba.ch\/blog\/wp-content\/uploads\/2015\/02\/02-300x135.png\" alt=\"02\" width=\"300\" height=\"135\" srcset=\"https:\/\/hasselba.ch\/blog\/wp-content\/uploads\/2015\/02\/02-300x135.png 300w, https:\/\/hasselba.ch\/blog\/wp-content\/uploads\/2015\/02\/02-1024x460.png 1024w, https:\/\/hasselba.ch\/blog\/wp-content\/uploads\/2015\/02\/02.png 1141w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>The request was made with my credentials, and that is why the &#8222;<em>Same origin-policy<\/em>&#8220; does not protect RESTful applications: If a victim visits my page, I am able perform malicious requests against a RESTful webservice in his context.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The &#8222;Same-orginin policy&#8222; is an important concept for protecting web applications. In short, only resources from the same domain are allowed, everything else is permitted denied. To allow access other domains in your application, you have to enable &#8222;CORS&#8222;, a &hellip; <a href=\"https:\/\/hasselba.ch\/blog\/?p=1995\">Weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9,61,35,81],"tags":[60,90,5,12],"class_list":["post-1995","post","type-post","status-publish","format-standard","hentry","category-javascript","category-rest","category-security","category-web","tag-rest","tag-security","tag-ssjs","tag-web"],"_links":{"self":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1995","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1995"}],"version-history":[{"count":11,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1995\/revisions"}],"predecessor-version":[{"id":2277,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=\/wp\/v2\/posts\/1995\/revisions\/2277"}],"wp:attachment":[{"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1995"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1995"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hasselba.ch\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1995"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}