-
Notifications
You must be signed in to change notification settings - Fork 35
/
index.html
263 lines (237 loc) · 14.3 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ"
crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/vs2015.min.css">
<link rel="stylesheet" href="../common/css/style.css">
</head>
<body>
<div class="container">
<div class="row">
<div class="col">
<p class="text-center header-text bold">Application Security and Hardening</p>
<p class="text-center header-text">Geekwise Academy</p>
<br>
<p class="text-center header-subtext italic">Week 6 - Authorization Continued and Server Hardening</p>
<br>
<p class="text-center header-subtext bold">Instructors:</p>
<p class="text-center header-subtext">Corey Shuman</p>
<p class="text-center header-subtext ta-name-full"></p>
<br>
<p class="text-center header-subtext bold">Slack Channel:</p>
<p class="text-center header-subtext"><a href="https://geekwise.slack.com/messages/C8SHHJQLU/">#application-security</a></p>
<p class="text-center header-subtext bold">Github Repo:</p>
<p class="text-center header-subtext"><a href="https://github.com/coreyshuman/GeekwiseApplicationSecurity">https://github.com/coreyshuman/GeekwiseApplicationSecurity</a></p>
<p class="text-center header-subtext bold">Lecture Notes:</p>
<p class="text-center header-subtext"><a href="http://coreyshuman.github.io/GeekwiseApplicationSecurity/LectureNotes">http://coreyshuman.github.io/GeekwiseApplicationSecurity/LectureNotes</a></p>
<hr><br>
</div>
</div>
<div class="row">
<div class="col">
<p class="header-subtext bold">Table of Contents:</p>
<ul id="table-of-contents"></ul>
<hr><br>
</div>
</div>
<div class="row">
<div class="col">
<h1>Authentication Continued</h1>
<p>This week we will continue to implement JWT authentication throughout our application.</p>
<h2>Storing JWT Tokens in the Browser</h2>
<p>Once a user has logged in and a JWT token has been created, it must be stored in the user's browser so that the
token can be added to the header on each subsequent API request.
</p>
<p>We could store the token in a variety of places. For this application, let's put it into Local Storage.</p>
<h3>Local Storage</h3>
<p>[Local Storage (Mozilla)](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage)</p>
<p>Modern browsers have a `localStorage` property on the window object which gives us access to a storage object for
the given domain's origin. We can set, get, and remove item's using the following methods:
</p>
<script type='template/code'>window.localStorage.setItem('jwtToken', 'aTexbdtHDse6Y...');</script>
<script type='template/code'>let jwtToken = window.localStorage.getItem('jwtToken');</script>
<script type='template/code'>window.localStorage.removeItem('jwtToken');</script>
<h2>Adding Headers to Requests</h2>
<p>[Request Object](https://developer.mozilla.org/en-US/docs/Web/API/Request/headers):</p>
<script type='template/code'>
var myHeaders = new Headers();
myHeaders.append('Content-Type', 'image/jpeg');
var myInit = { method: 'GET',
headers: myHeaders,
mode: 'cors',
cache: 'default' };
var myRequest = new Request('flowers.jpg',myInit);
myContentType = myRequest.headers.get('Content-Type'); // returns 'image/jpeg'
</script>
<p>[AJAX](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader):</p>
<script type='template/code'>
$.ajax({
url: 'https://api.sandbox.slcedu.org/api/rest/v1/students/test1',
type: 'GET',
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', 'Bearer t-7614f875-8423-4f20-a674-d7cf3096290e');
},
data: {},
success: function () { },
error: function () { },
});
</script>
<div class='outline'>
<h2>In Class: Let's Use JWT and Request Headers Together</h2>
<ul>
<li>Use `Local Storage` to save the JWT token after logging in.</li>
<li>Attach the stored JWT token to the home page's `GET /post` request.</li>
</ul>
</div>
<div class='outline'>
<h1>In Class Lab Assignment</h1>
<p>The application is currently wired up to work on a single server using cookies and form submits. We will work
together to add a second mode of operation which will allow our application to work with JWT Tokens and an
API server.
</p>
</div>
<br>
<hr>
<h1>Application Hardening - Best Practices</h1>
<p>In this section, we will look at a variety of tools and settings we can use to harden our application against common
vulnerabilities. We will use the [ExpressJS Best Practice Security](https://expressjs.com/en/advanced/best-practice-security.html)
resource as a starting point.
</p>
<p>When using ExpressJS, the "easy" solution is to install [Helmet](https://www.npmjs.com/package/helmet), which is
a collection of smaller middleware functions designed to secure a web app. We will look at some of those smaller
functions in detail today so that we understand the underlying vulnerabilities and their accompanying solutions.
</p>
<h2>Content Security Policy</h2>
<p>[Reference](https://content-security-policy.com/)</p>
<p>[Browser Test](https://content-security-policy.com/browser-test/)</p>
<p>The `Content-Security-Policy` is a fairly new HTTP response header which allows us to reduce the risk of XSS on
modern broswers by declaring what dynamic resources are allowed to load. The header value is made up of one or
more directives separated with a semicolon `;`. The reference above provides a full list of all CSP directives.
The following example is a good starting place for most apps:
</p>
<script type='template/code' class='javascript'>default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self';</script>
<p>This example allows images, scripts, AJAX, and CSS from the same origin, and does not allow any other resources
to load.</p>
<h2>X-Powered-By Header</h2>
<p>The `X-Powered-By` header can allow hackers to target specific vulnerabilities of our server framework if we declare
which server we are using in the header. Disabling this header provides us some [security through obscurity](https://en.wikipedia.org/wiki/Security_through_obscurity).
All we need in our code is the following:
</p>
<script type='template/code'>app.disable('x-powered-by');</script>
<h2>Cache-Control Header</h2>
<p>As Internet speeds and caps are increasing, security is taking precedence over caching and efficiency. If you have
old versions of HTML or Scripts cached on client machines, they could be left vulnerable long after you have
fixed a bug. The following four headers are used to disable most browser caching:
</p>
<script type='template/code' class='javascript'>
Cache-Control: no-store, no-cache, must-revalidate, proxy-revalidate
Pragma: no-cache
Expires: 0
Surrogate-Control: no-store
</script>
<p>This of course will negate the performace benefits of caching and may not be a good fit for all applications. As
an alternative, bundled resources can be cached and versioned by changing the name of the file when a new version
is released. This will inherently bust the cache and load the new file version. </p>
<p>More on that topic here: [Revving Filenames](http://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/)
</p>
<h2>X-Frame-Options Header</h2>
<p>The `X-Frame-Options` header restricts which sites put your site into an iframe. For example, on my site (`http://coreyshuman.com`)
I could include an iframe with `example.com`. The `X-Frame-Options` that `example.com` chooses will control whether
the iframe is allowed or not.
</p>
<p>`X-Frame-Options` has 3 options: `DENY`, `SAMEORIGIN`, and `ALLOW-FROM`. `DENY` will prevent your site from appearing
in any iframes. `SAMEORIGIN` will allow your site to be included in frames from the same origin. `ALLOW-FROM`
will let you pick specific domains that are allowed to include your site in an iframe.
</p>
<p>To test this, try including an iframe with `src='google.com'` on your site. Google's `X-Frame-Options` is set to
`SAMEORIGIN`, so the iframe will refuse to load.
</p>
<h2>X-XSS-Protection Header</h2>
<p>[Mozilla X-XSS-Protection Reference](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection)</p>
<p>The `X-XSS-Protection` header stops pages from loading when they detect a reflected coss-site scripting (XSS) attack.
This was initially a feature of Internet Explorer, but Chrome and Safari have adopted the header.
</p>
<p>This feature has mostly been replaced by using strong Content-Security-Policy settings, but is still used commonly
to protect older browsers that don't yet support CSP.
</p>
<h2>Cookie Security Options</h2>
<p>Consider signing or encrypting cookies to ensure they are not tampered with. In our app, we use `cookie-session`
to sign our session cookie. Additionally, avoid using the default session cookie name as this can open our app
to target attacks. Instead use generic cookie names. For example:
</p>
<script type='template/code'>
var session = require('cookie-session')
app.set('trust proxy', 1) // trust first proxy
app.use(session({
secret: 's3cr3tp4ss',
name: 'sessionId' // this is the generic session name
}))
</script>
<p>As an aside, explanation of the `trust proxy` setting can be found here: [ExpressJS Behind Proxies](https://expressjs.com/en/guide/behind-proxies.html)</p>
<p>Set the following cookie options to enhance security:
<ul>
<li>**secure** - Ensures the browser only sends the cookie over HTTPS.</li>
<li>**httpOnly** - Ensures the cookie is sent only over HTTP(S), not client JavaScript, helping to protect against
cross-site scripting attacks.</li>
<li>**domain** - indicates the domain of the cookie; use it to compare against the domain of the server in which
the URL is being requested. If they match, then check the path attribute next.</li>
<li>**path** - indicates the path of the cookie; use it to compare against the request path. If this and domain
match, then send the cookie in the request.</li>
<li>**expires** - use to set expiration date for persistent cookies.</li>
</ul>
</p>
<div class='outline'>
<h2>In Class: Content-Security-Policy Project</h2>
<p>We will each build a simple test page to demonstrate a feature of CSP. Each person will work on a different protection
component in CSP. For example, `script-src`, `img-src`, or `style-src`. The goal is to build an injection based
around your specific component, then show how CSP rules can prevent the vulnerability from running. Use the
[CSP Browser Test](https://content-security-policy.com/browser-test/) for inspiration.
</p>
</div>
</div>
<!-- End Col-->
</div>
<div class="row">
<div class="col">
<br>
<hr>
<h1 class="header-subtext bold">Resources</h1>
<ul id="resources"></ul>
</div>
</div>
</div>
<!--Footer-->
<br><br>
<footer class="page-footer">
<div style="background-color: #b9b9b9;">
<!-- Copyright-->
<div class="footer-copyright">
<div class="container-fluid text-center">
© 2017 -
<script type="text/javascript">
document.write(new Date().getFullYear());
</script>
<a href="https://geekwiseacademy.com">Geekwise Academy</a> & <a href="http://coreyshuman.com">Corey Shuman</a>
</div>
</div>
<!--/.Copyright -->
</div>
</footer>
<!--/.Footer-->
<!-- jQuery first, then Tether, then Bootstrap JS. -->
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb"
crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn"
crossorigin="anonymous"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
<script src="../common/js/scripts.js"></script>
<script src="../common/js/ta-name.js"></script>
</body>
</html>