Skip to content

Commit f64b10d

Browse files
Added html escaping to help with XSS. Added frame busting to help with XFS. Added a method override filter so that only GETs and POSTs are accepted. Disabled autocomplete for password fields. Added ability for customer to set their HPKP headers.
1 parent f0700bb commit f64b10d

15 files changed

+167
-12
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2014-2017 Ping Identity Corporation
3+
* All Rights Reserved.
4+
*/
5+
6+
package com.unboundid.webapp.ssam;
7+
8+
import org.springframework.stereotype.Component;
9+
import javax.servlet.FilterConfig;
10+
import javax.servlet.ServletRequest;
11+
import javax.servlet.ServletResponse;
12+
import javax.servlet.FilterChain;
13+
import javax.servlet.http.HttpServletResponse;
14+
15+
@Component
16+
public class HTTPHeaderFilter implements javax.servlet.Filter {
17+
public FilterConfig filterConfig;
18+
19+
public void doFilter(final ServletRequest request,
20+
final ServletResponse response, FilterChain chain)
21+
throws java.io.IOException, javax.servlet.ServletException {
22+
23+
HttpServletResponse res = (HttpServletResponse) response;
24+
25+
// Set this variable to the sha256 pin of your public key
26+
// This value can be generated using the "openssl" command line tool
27+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning
28+
String pinSha256 = "";
29+
30+
if(pinSha256.length() > 0)
31+
{
32+
res.setHeader("Public-Key-Pins", "max-age=518400; " +
33+
"pin-sha256=\"" + pinSha256 + "\"; " +
34+
"includeSubDomains");
35+
}
36+
37+
chain.doFilter(request, response);
38+
}
39+
40+
public void init(final FilterConfig filterConfig) { this.filterConfig = filterConfig; }
41+
42+
public void destroy() {}
43+
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright 2014-2017 Ping Identity Corporation
3+
* All Rights Reserved.
4+
*/
5+
6+
package com.unboundid.webapp.ssam;
7+
8+
import org.springframework.stereotype.Component;
9+
import javax.servlet.FilterConfig;
10+
import javax.servlet.ServletRequest;
11+
import javax.servlet.ServletResponse;
12+
import javax.servlet.FilterChain;
13+
import javax.servlet.http.HttpServletRequest;
14+
15+
@Component
16+
public class HTTPRequestParameterFilter implements javax.servlet.Filter {
17+
public FilterConfig filterConfig;
18+
19+
public void doFilter(final ServletRequest request,
20+
final ServletResponse response, FilterChain chain)
21+
throws java.io.IOException, javax.servlet.ServletException {
22+
23+
String curMethod = ((HttpServletRequest) request).getMethod();
24+
//only allow for GET and POST requests.
25+
if (curMethod.equalsIgnoreCase("get") || curMethod.equalsIgnoreCase("post"))
26+
{
27+
chain.doFilter(request, response);
28+
}
29+
}
30+
31+
public void init(final FilterConfig filterConfig) {
32+
this.filterConfig = filterConfig;
33+
}
34+
public void destroy() {}
35+
}

Diff for: src/main/java/com/unboundid/webapp/ssam/SSAMController.java

+3-2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import org.springframework.web.bind.annotation.RequestParam;
4545
import org.springframework.web.bind.annotation.ResponseBody;
4646
import org.springframework.web.client.RestTemplate;
47+
import org.springframework.web.util.HtmlUtils;
4748

4849
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4950
import com.fasterxml.jackson.annotation.JsonProperty;
@@ -971,7 +972,7 @@ private void populateUserModel(String username, Entry entry, Model model)
971972
model.addAttribute("username", username);
972973
for(Attribute attribute : entry.getAttributes())
973974
{
974-
model.addAttribute(attribute.getName(), attribute.getValue());
975+
model.addAttribute(attribute.getName(), HtmlUtils.htmlEscape(attribute.getValue()));
975976
}
976977
model.addAttribute("entry", entry);
977978
}
@@ -989,7 +990,7 @@ private void populateRegistrationModel(Map<String, String> parameters,
989990
String value = parameter.getValue().trim();
990991
if(!value.isEmpty())
991992
{
992-
model.addAttribute(name, value);
993+
model.addAttribute(name, HtmlUtils.htmlEscape(value));
993994
}
994995
}
995996
}

Diff for: src/main/resources/static/css/ssam.css

+9
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
/*
2+
* None style added to help with Frame Busting
3+
* intended for older browsers without 'X-Frame-Options' header support.
4+
* This method comes from an OWASP write up by Gustav Rydstedt.
5+
*/
6+
html {
7+
display: none;
8+
}
9+
110
.navbar-static-top {
211
margin-bottom: 19px;
312
}

Diff for: src/main/resources/static/js/ssam-security-patch.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// frame busting
2+
function buster(document_in, top_in) {
3+
if (self === top_in) {
4+
document_in.documentElement.style.display = "block";
5+
} else {
6+
top_in.location = self.location;
7+
}
8+
}
9+
10+
// html escaping for potentially unsafe jQuery methods such as ".append()"
11+
var entityMap = {
12+
'&': '&amp;',
13+
'<': '&lt;',
14+
'>': '&gt;',
15+
'"': '&quot;',
16+
"'": '&#x27;',
17+
'/': '&#x2F;',
18+
'`': '&#x60;',
19+
'=': '&#x3D;'
20+
};
21+
22+
function escapeHtml (string) {
23+
return String(string).replace(/[&<>"'`=\/]/g, function (s) {
24+
return entityMap[s];
25+
});
26+
}

Diff for: src/main/resources/templates/deletion-success.vm

+5-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@
2525
</div>
2626
</div>
2727
</div>
28-
28+
29+
<script src="js/ssam-security-patch.js"></script>
30+
<script type="text/javascript">
31+
buster(document, top);
32+
</script>
2933
<script src="js/jquery-2.1.4.min.js"></script>
3034
<script src="js/bootstrap.min.js"></script>
3135
<script src="js/ssam.js"></script>

Diff for: src/main/resources/templates/error.vm

+4
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,9 @@
1313
<div class="container">
1414
Something went wrong: $!status $error
1515
</div>
16+
<script src="js/ssam-security-patch.js"></script>
17+
<script type="text/javascript">
18+
buster(document, top);
19+
</script>
1620
</body>
1721
</html>

Diff for: src/main/resources/templates/login.vm

+5-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
<label for="inputUsername" class="sr-only">Email/Username</label>
2323
<input type="text" id="inputUsername" name="username" class="form-control" placeholder="Email/Username" required autofocus>
2424
<label for="inputPassword" class="sr-only">Password</label>
25-
<input type="password" id="inputPassword" name="password" class="form-control" placeholder="Password" required>
25+
<input type="password" id="inputPassword" name="password" class="form-control" placeholder="Password" autocomplete="off" required>
2626
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
2727
<div style="margin-top: 5px;">
2828
<a href="recoverPassword">Forgot password?</a>
@@ -31,6 +31,10 @@
3131
</div>
3232
</form>
3333
</div>
34+
<script src="js/ssam-security-patch.js"></script>
35+
<script type="text/javascript">
36+
buster(document, top);
37+
</script>
3438
<script src="js/jquery-2.1.4.min.js"></script>
3539
<script src="js/bootstrap.min.js"></script>
3640
</body>

Diff for: src/main/resources/templates/recover-password-success.vm

+5-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@
2525
</div>
2626
</div>
2727
</div>
28-
28+
29+
<script src="js/ssam-security-patch.js"></script>
30+
<script type="text/javascript">
31+
buster(document, top);
32+
</script>
2933
<script src="js/jquery-2.1.4.min.js"></script>
3034
<script type="text/javascript">
3135
$(document).ready(function() {

Diff for: src/main/resources/templates/recover-password-verify.vm

+4
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@
9090
</div>
9191
</div>
9292

93+
<script src="js/ssam-security-patch.js"></script>
94+
<script type="text/javascript">
95+
buster(document, top);
96+
</script>
9397
<script src="js/jquery-2.1.4.min.js"></script>
9498
<script src="js/bootstrap.min.js"></script>
9599
<script src="js/ssam.js"></script>

Diff for: src/main/resources/templates/recover-password.vm

+4
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@
5151
</div>
5252
</div>
5353

54+
<script src="js/ssam-security-patch.js"></script>
55+
<script type="text/javascript">
56+
buster(document, top);
57+
</script>
5458
<script src="js/jquery-2.1.4.min.js"></script>
5559
<script src="js/bootstrap.min.js"></script>
5660
<script src="js/ssam.js"></script>

Diff for: src/main/resources/templates/register.vm

+4
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@
9393
</div>
9494
</div>
9595

96+
<script src="js/ssam-security-patch.js"></script>
97+
<script type="text/javascript">
98+
buster(document, top);
99+
</script>
96100
<script src="js/jquery-2.1.4.min.js"></script>
97101
<script src="js/bootstrap.min.js"></script>
98102
<script src="js/ssam.js"></script>

Diff for: src/main/resources/templates/registration-success.vm

+5-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@
2525
</div>
2626
</div>
2727
</div>
28-
28+
29+
<script src="js/ssam-security-patch.js"></script>
30+
<script type="text/javascript">
31+
buster(document, top);
32+
</script>
2933
<script src="js/jquery-2.1.4.min.js"></script>
3034
<script src="js/bootstrap.min.js"></script>
3135
<script src="js/ssam.js"></script>

Diff for: src/main/resources/templates/registration-verify.vm

+5-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,11 @@
5656
</div>
5757
</div>
5858
</div>
59-
59+
60+
<script src="js/ssam-security-patch.js"></script>
61+
<script type="text/javascript">
62+
buster(document, top);
63+
</script>
6064
<script src="js/jquery-2.1.4.min.js"></script>
6165
<script src="js/bootstrap.min.js"></script>
6266
<script src="js/ssam.js"></script>

Diff for: src/main/resources/templates/user.vm

+9-5
Original file line numberDiff line numberDiff line change
@@ -113,20 +113,20 @@
113113
<div class="form-group">
114114
<label class="col-sm-4 control-label">Current Password </label>
115115
<div class="col-sm-8">
116-
<input id="currentPassword" type="password" class="form-control" placeholder="Enter Current Password">
116+
<input id="currentPassword" type="password" class="form-control" placeholder="Enter Current Password" autocomplete="off">
117117
</div>
118118
</div>
119119
<div class="form-group">
120120
<label class="col-sm-4 control-label">Password </label>
121121
<div class="col-sm-8">
122-
<input id="password" type="password" class="form-control" placeholder="Enter New Password">
122+
<input id="password" type="password" class="form-control" placeholder="Enter New Password" autocomplete="off">
123123
#parse("_password-requirements.vm")
124124
</div>
125125
</div>
126126
<div class="form-group">
127127
<label class="col-sm-4 control-label">Confirm&nbsp;Password </label>
128128
<div class="col-sm-8">
129-
<input id="confirmPassword" type="password" class="form-control" placeholder="Re-Enter New Password">
129+
<input id="confirmPassword" type="password" class="form-control" placeholder="Re-Enter New Password" autocomplete="off">
130130
</div>
131131
</div>
132132
</form>
@@ -161,6 +161,10 @@
161161
</div>
162162
</div>
163163
#end
164+
<script src="js/ssam-security-patch.js"></script>
165+
<script type="text/javascript">
166+
buster(document, top);
167+
</script>
164168
<script src="js/jquery-2.1.4.min.js"></script>
165169
<script src="js/bootstrap.min.js"></script>
166170
<script src="js/ssam.js"></script>
@@ -277,8 +281,8 @@
277281
cn = first + " " + last;
278282
}
279283
var address = cn + '$' + $('input[name="street"]').val().trim() + '$' + $('input[name="l"]').val().trim() + ', ' + $('input[name="st"]').val().trim() + ' ' + $('input[name="postalCode"]').val().trim();
280-
userForm.append('<input type="hidden" name="cn" value="' + cn + '">');
281-
userForm.append('<input type="hidden" name="postalAddress" value="' + address + '">');
284+
userForm.append('<input type="hidden" name="cn" value="' + escapeHtml(cn) + '">');
285+
userForm.append('<input type="hidden" name="postalAddress" value="' + escapeHtml(address) + '">');
282286
userForm.submit();
283287
});
284288
});

0 commit comments

Comments
 (0)