Commit 3a6976f0 authored by Dave Cridland's avatar Dave Cridland

OF-777 CVE-2015-6973 CSRF protection (partial)

Extending the previous commit, this adds CSRF to a number of high-value target
pages, including user password changing, dleetion, lockout, etc, and also for
the login page (to avoid a class of attack we probably don't care about).

The CSRF mechanism requires manual addition to each form, but has been
design reviewed by Simon Waters (Surevine Ltd).
parent ce87ab79
......@@ -126,6 +126,7 @@ public class CookieUtils {
Cookie cookie = new Cookie(name, value);
cookie.setMaxAge(maxAge);
cookie.setPath(path);
cookie.setHttpOnly(true);
response.addCookie(cookie);
}
}
......@@ -86,7 +86,21 @@
Map<String, String> errors = new HashMap<String, String>();
if (ParamUtils.getBooleanParameter(request, "login")) {
Boolean login = ParamUtils.getBooleanParameter(request, "login");
Cookie csrfCookie = CookieUtils.getCookie(request, "csrf");
String csrfParam = ParamUtils.getParameter(request, "csrf");
if (login) {
if (csrfCookie == null || csrfParam == null || !csrfCookie.getValue().equals(csrfParam)) {
login = false;
errors.put("csrf", "CSRF Failure!");
}
}
csrfParam = StringUtils.randomString(15);
CookieUtils.setCookie(request, response, "csrf", csrfParam, -1);
pageContext.setAttribute("csrf", csrfParam);
if (login) {
String loginUsername = username;
if (loginUsername != null) {
loginUsername = JID.escapeNode(loginUsername);
......@@ -182,6 +196,7 @@
<% } catch (Exception e) { Log.error(e); } } %>
<input type="hidden" name="login" value="true">
<input type="hidden" name="csrf" value="${csrf}">
<div align="center">
<!-- BEGIN login box -->
......
......@@ -45,8 +45,20 @@
String password = ParamUtils.getParameter(request,"password");
String passwordConfirm = ParamUtils.getParameter(request,"passwordConfirm");
boolean isAdmin = ParamUtils.getBooleanParameter(request,"isadmin");
Cookie csrfCookie = CookieUtils.getCookie(request, "csrf");
String csrfParam = ParamUtils.getParameter(request, "csrf");
Map<String, String> errors = new HashMap<String, String>();
if (create) {
if (csrfCookie == null || csrfParam == null || !csrfCookie.getValue().equals(csrfParam)) {
create = false;
errors.put("csrf", "CSRF Failure!");
}
}
csrfParam = StringUtils.randomString(15);
CookieUtils.setCookie(request, response, "csrf", csrfParam, -1);
pageContext.setAttribute("csrf", csrfParam);
// Handle a cancel
if (cancel) {
response.sendRedirect("user-summary.jsp");
......@@ -203,6 +215,7 @@
<% } %>
<form name="f" action="user-create.jsp" method="get">
<input type="hidden" name="csrf" value="${csrf}">
<div class="jive-contentBoxHeader">
<fmt:message key="user.create.new_user" />
......
......@@ -25,6 +25,7 @@
<%@ page import="org.jivesoftware.openfire.user.UserManager" %>
<%@ page import="org.jivesoftware.util.ParamUtils" %>
<%@ page import="org.jivesoftware.util.StringUtils" %>
<%@ page import="org.jivesoftware.util.CookieUtils" %>
<%@ page import="org.xmpp.packet.JID" %>
<%@ page import="org.xmpp.packet.StreamError" %>
<%@ page import="java.net.URLEncoder" %>
......@@ -39,6 +40,17 @@
boolean cancel = request.getParameter("cancel") != null;
boolean delete = request.getParameter("delete") != null;
String username = ParamUtils.getParameter(request,"username");
Cookie csrfCookie = CookieUtils.getCookie(request, "csrf");
String csrfParam = ParamUtils.getParameter(request, "csrf");
if (delete) {
if (csrfCookie == null || csrfParam == null || !csrfCookie.getValue().equals(csrfParam)) {
delete = false;
}
}
csrfParam = StringUtils.randomString(15);
CookieUtils.setCookie(request, response, "csrf", csrfParam, -1);
pageContext.setAttribute("csrf", csrfParam);
// Handle a cancel
if (cancel) {
......@@ -107,6 +119,7 @@
</c:if>
<form action="user-delete.jsp">
<input type="hidden" name="csrf" value="${csrf}">
<input type="hidden" name="username" value="<%= StringUtils.escapeForXML(username) %>">
<input type="submit" name="delete" value="<fmt:message key="user.delete.delete" />">
<input type="submit" name="cancel" value="<fmt:message key="global.cancel" />">
......
......@@ -45,19 +45,21 @@
Map<String, String> errors = new HashMap<String, String>();
Cookie csrfCookie = CookieUtils.getCookie(request, "csrf");
String csrfParam = ParamUtils.getParameter(request, "csrf");
// Handle a cancel
if (request.getParameter("cancel") != null) {
response.sendRedirect("user-properties.jsp?username=" + URLEncoder.encode(username, "UTF-8"));
return;
}
if (save) {
if (csrfCookie == null || csrfParam == null || !csrfCookie.getValue().equals(csrfParam)) {
save = false;
errors.put("csrf", "CSRF Failure");
}
}
csrfParam = StringUtils.randomString(15);
CookieUtils.setCookie(request, response, "csrf", csrfParam, -1);
pageContext.setAttribute("csrf", csrfParam);
// Handle a cancel
if (request.getParameter("cancel") != null) {
response.sendRedirect("user-properties.jsp?username=" + URLEncoder.encode(username, "UTF-8"));
return;
}
// Load the user object
User user = webManager.getUserManager().getUser(username);
......@@ -101,9 +103,6 @@
return;
}
}
csrfParam = StringUtils.randomString(15);
CookieUtils.setCookie(request, response, "csrf", csrfParam, -1);
%>
<html>
......@@ -157,7 +156,7 @@
<form action="user-edit-form.jsp">
<input type="hidden" name="csrf" value="<%= StringUtils.escapeForXML(csrfParam) %>">
<input type="hidden" name="csrf" value="${csrf}">
<input type="hidden" name="username" value="<%= StringUtils.escapeForXML(username) %>">
<input type="hidden" name="save" value="true">
......
......@@ -25,6 +25,7 @@
<%@ page import="org.jivesoftware.openfire.session.ClientSession" %>
<%@ page import="org.jivesoftware.util.ParamUtils" %>
<%@ page import="org.jivesoftware.util.StringUtils" %>
<%@ page import="org.jivesoftware.util.CookieUtils" %>
<%@ page import="org.xmpp.packet.JID" %>
<%@ page import="org.xmpp.packet.StreamError" %>
<%@ page import="java.net.URLEncoder" %>
......@@ -50,6 +51,17 @@
if (duration == -2) {
duration = ParamUtils.getIntParameter(request,"duration_custom", -1);
}
Cookie csrfCookie = CookieUtils.getCookie(request, "csrf");
String csrfParam = ParamUtils.getParameter(request, "csrf");
if (lock || unlock) {
if (csrfCookie == null || csrfParam == null || !csrfCookie.getValue().equals(csrfParam)) {
lock = false;
unlock = false;
}
}
csrfParam = StringUtils.randomString(15);
CookieUtils.setCookie(request, response, "csrf", csrfParam, -1);
pageContext.setAttribute("csrf", csrfParam);
// Handle a cancel
if (cancel) {
......@@ -146,6 +158,7 @@
<form action="user-lockout.jsp">
<input type="hidden" name="username" value="${usernameHtmlEscaped}">
<input type="hidden" name="csrf" value="${csrf}">
<input type="submit" name="unlock" value="<fmt:message key="user.lockout.unlock" />">
<input type="submit" name="cancel" value="<fmt:message key="global.cancel" />">
</form>
......@@ -169,6 +182,7 @@
</c:if>
<form action="user-lockout.jsp">
<input type="hidden" name="csrf" value="${csrf}">
<% if (LockOutManager.getLockOutProvider().isDelayedStartSupported()) { %>
<b><fmt:message key="user.lockout.time.startdelay" /></b><br />
<input type="radio" name="startdelay" value="-1" checked="checked" /> <fmt:message key="user.lockout.time.immediate" /><br />
......
......@@ -35,6 +35,17 @@
String username = ParamUtils.getParameter(request,"username");
String password = ParamUtils.getParameter(request,"password");
String passwordConfirm = ParamUtils.getParameter(request,"passwordConfirm");
Cookie csrfCookie = CookieUtils.getCookie(request, "csrf");
String csrfParam = ParamUtils.getParameter(request, "csrf");
if (update) {
if (csrfCookie == null || csrfParam == null || !csrfCookie.getValue().equals(csrfParam)) {
update = false;
}
}
csrfParam = StringUtils.randomString(15);
CookieUtils.setCookie(request, response, "csrf", csrfParam, -1);
pageContext.setAttribute("csrf", csrfParam);
// Handle a cancel
if (cancel) {
......@@ -133,6 +144,7 @@
<form action="user-password.jsp" name="passform" method="post">
<input type="hidden" name="username" value="<%=StringUtils.escapeForXML(username) %>">
<input type="hidden" name="csrf" value="${csrf}">
<fieldset>
<legend><fmt:message key="user.password.change" /></legend>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment