Headline
CVE-2018-25084: Added html escaping to help with XSS. Added frame busting to help wit… · pingidentity/ssam@f64b10d
A vulnerability, which was classified as problematic, has been found in Ping Identity Self-Service Account Manager 1.1.2. Affected by this issue is some unknown functionality of the file src/main/java/com/unboundid/webapp/ssam/SSAMController.java. The manipulation leads to cross site scripting. The attack may be launched remotely. Upgrading to version 1.1.3 is able to address this issue. The name of the patch is f64b10d63bb19ca2228b0c2d561a1a6e5a3bf251. It is recommended to upgrade the affected component. VDB-225362 is the identifier assigned to this vulnerability.
@@ -0,0 +1,44 @@
/*
* Copyright 2014-2017 Ping Identity Corporation
* All Rights Reserved.
*/
package com.unboundid.webapp.ssam;
import org.springframework.stereotype.Component;
import javax.servlet.FilterConfig;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletResponse;
@Component
public class HTTPHeaderFilter implements javax.servlet.Filter {
public FilterConfig filterConfig;
public void doFilter(final ServletRequest request,
final ServletResponse response, FilterChain chain)
throws java.io.IOException, javax.servlet.ServletException {
HttpServletResponse res = (HttpServletResponse) response;
// Set this variable to the sha256 pin of your public key
// This value can be generated using the “openssl” command line tool
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Public_Key_Pinning
String pinSha256 = "";
if(pinSha256.length() > 0)
{
res.setHeader("Public-Key-Pins", "max-age=518400; " +
“pin-sha256=\"” + pinSha256 + "\"; " +
“includeSubDomains”);
}
chain.doFilter(request, response);
}
public void init(final FilterConfig filterConfig) { this.filterConfig = filterConfig; }
public void destroy() {}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2014-2017 Ping Identity Corporation
* All Rights Reserved.
*/
package com.unboundid.webapp.ssam;
import org.springframework.stereotype.Component;
import javax.servlet.FilterConfig;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
@Component
public class HTTPRequestParameterFilter implements javax.servlet.Filter {
public FilterConfig filterConfig;
public void doFilter(final ServletRequest request,
final ServletResponse response, FilterChain chain)
throws java.io.IOException, javax.servlet.ServletException {
String curMethod = ((HttpServletRequest) request).getMethod();
//only allow for GET and POST requests.
if (curMethod.equalsIgnoreCase(“get”) || curMethod.equalsIgnoreCase(“post”))
{
chain.doFilter(request, response);
}
}
public void init(final FilterConfig filterConfig) {
this.filterConfig = filterConfig;
}
public void destroy() {}
}
@@ -44,6 +44,7 @@
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.HtmlUtils;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
@@ -971,7 +972,7 @@ private void populateUserModel(String username, Entry entry, Model model)
model.addAttribute("username", username);
for(Attribute attribute : entry.getAttributes())
{
model.addAttribute(attribute.getName(), attribute.getValue());
model.addAttribute(attribute.getName(), HtmlUtils.htmlEscape(attribute.getValue()));
}
model.addAttribute("entry", entry);
}
@@ -989,7 +990,7 @@ private void populateRegistrationModel(Map<String, String> parameters,
String value = parameter.getValue().trim();
if(!value.isEmpty())
{
model.addAttribute(name, value);
model.addAttribute(name, HtmlUtils.htmlEscape(value));
}
}
}
@@ -1,3 +1,12 @@
/*
* None style added to help with Frame Busting
* intended for older browsers without ‘X-Frame-Options’ header support.
* This method comes from an OWASP write up by Gustav Rydstedt.
*/
html {
display: none;
}
.navbar-static-top {
margin-bottom: 19px;
}
@@ -0,0 +1,26 @@
// frame busting
function buster(document_in, top_in) {
if (self === top_in) {
document_in.documentElement.style.display = "block";
} else {
top_in.location = self.location;
}
}
// html escaping for potentially unsafe jQuery methods such as ".append()"
var entityMap = {
'&’: '&’,
'<’: '<’,
'>’: '>’,
'"’: '"’,
"’": '’’,
'/’: '/’,
'`’: '`’,
'=’: ‘=’
};
function escapeHtml (string) {
return String(string).replace(/[&<>"’`=\/]/g, function (s) {
return entityMap[s];
});
}
@@ -25,7 +25,11 @@
</div>
</div>
</div>
<script src="js/ssam-security-patch.js"></script>
<script type="text/javascript">
buster(document, top);
</script>
<script src="js/jquery-2.1.4.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/ssam.js"></script>
@@ -13,5 +13,9 @@
<div class="container">
Something went wrong: $!status $error
</div>
<script src="js/ssam-security-patch.js"></script>
<script type="text/javascript">
buster(document, top);
</script>
</body>
</html>
@@ -22,7 +22,7 @@
<label for="inputUsername" class="sr-only">Email/Username</label>
<input type="text" id="inputUsername" name="username" class="form-control" placeholder="Email/Username" required autofocus>
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" id="inputPassword" name="password" class="form-control" placeholder="Password" required>
<input type="password" id="inputPassword" name="password" class="form-control" placeholder="Password" autocomplete="off" required>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
<div style="margin-top: 5px;">
<a href="recoverPassword">Forgot password?</a>
@@ -31,6 +31,10 @@
</div>
</form>
</div>
<script src="js/ssam-security-patch.js"></script>
<script type="text/javascript">
buster(document, top);
</script>
<script src="js/jquery-2.1.4.min.js"></script>
<script src="js/bootstrap.min.js"></script>
</body>
@@ -25,7 +25,11 @@
</div>
</div>
</div>
<script src="js/ssam-security-patch.js"></script>
<script type="text/javascript">
buster(document, top);
</script>
<script src="js/jquery-2.1.4.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
@@ -90,6 +90,10 @@
</div>
</div>
<script src="js/ssam-security-patch.js"></script>
<script type="text/javascript">
buster(document, top);
</script>
<script src="js/jquery-2.1.4.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/ssam.js"></script>
@@ -51,6 +51,10 @@
</div>
</div>
<script src="js/ssam-security-patch.js"></script>
<script type="text/javascript">
buster(document, top);
</script>
<script src="js/jquery-2.1.4.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/ssam.js"></script>
@@ -93,6 +93,10 @@
</div>
</div>
<script src="js/ssam-security-patch.js"></script>
<script type="text/javascript">
buster(document, top);
</script>
<script src="js/jquery-2.1.4.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/ssam.js"></script>
@@ -25,7 +25,11 @@
</div>
</div>
</div>
<script src="js/ssam-security-patch.js"></script>
<script type="text/javascript">
buster(document, top);
</script>
<script src="js/jquery-2.1.4.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/ssam.js"></script>
@@ -56,7 +56,11 @@
</div>
</div>
</div>
<script src="js/ssam-security-patch.js"></script>
<script type="text/javascript">
buster(document, top);
</script>
<script src="js/jquery-2.1.4.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/ssam.js"></script>
@@ -113,20 +113,20 @@
<div class="form-group">
<label class="col-sm-4 control-label">Current Password </label>
<div class="col-sm-8">
<input id="currentPassword" type="password" class="form-control" placeholder="Enter Current Password">
<input id="currentPassword" type="password" class="form-control" placeholder="Enter Current Password" autocomplete="off">
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">Password </label>
<div class="col-sm-8">
<input id="password" type="password" class="form-control" placeholder="Enter New Password">
<input id="password" type="password" class="form-control" placeholder="Enter New Password" autocomplete="off">
#parse(“_password-requirements.vm”)
</div>
</div>
<div class="form-group">
<label class="col-sm-4 control-label">Confirm Password </label>
<div class="col-sm-8">
<input id="confirmPassword" type="password" class="form-control" placeholder="Re-Enter New Password">
<input id="confirmPassword" type="password" class="form-control" placeholder="Re-Enter New Password" autocomplete="off">
</div>
</div>
</form>
@@ -161,6 +161,10 @@
</div>
</div>
#end
<script src="js/ssam-security-patch.js"></script>
<script type="text/javascript">
buster(document, top);
</script>
<script src="js/jquery-2.1.4.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/ssam.js"></script>
@@ -277,8 +281,8 @@
cn = first + " " + last;
}
var address = cn + ‘$’ + $('input[name="street"]').val().trim() + ‘$’ + $('input[name="l"]').val().trim() + ', ' + $('input[name="st"]').val().trim() + ' ' + $('input[name="postalCode"]').val().trim();
userForm.append(‘<input type="hidden" name="cn" value="’ + cn + ‘">’);
userForm.append(‘<input type="hidden" name="postalAddress" value="’ + address + ‘">’);
userForm.append(‘<input type="hidden" name="cn" value="’ + escapeHtml(cn) + ‘">’);
userForm.append(‘<input type="hidden" name="postalAddress" value="’ + escapeHtml(address) + ‘">’);
userForm.submit();
});
});