Skip to content

Instantly share code, notes, and snippets.

@SharkFourSix
Last active July 2, 2019 15:14
Show Gist options
  • Save SharkFourSix/798a6c46151496837d290428ab661d7b to your computer and use it in GitHub Desktop.
Save SharkFourSix/798a6c46151496837d290428ab661d7b to your computer and use it in GitHub Desktop.
Anti-XSRF Cookies in Spark Java using 'SameSite' flag
import javax.servlet.http.Cookie;
import java.text.DateFormat;
import java.util.Date;
import java.util.TimeZone;
public final class AntiXsrfCookie extends Cookie {
private static final String SAME_SITE_LAX = "Lax";
private static final String SAME_SITE_STRICT = "Strict";
private String sameSite = SAME_SITE_STRICT;
public AntiXsrfCookie(String name, String value) {
super(name, value);
}
@Override
public String toString() {
final DateFormat dateFormat = DateFormat.getInstance();
final StringBuilder sb = new StringBuilder();
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
sb.append(getName()).append("=").append(getValue())
.append(";Expires=").append(dateFormat.format(new Date(System.currentTimeMillis() + getMaxAge())))
.append(";Max-Age=").append(getMaxAge())
.append(";Path=").append(getPath())
.append(";Domain=").append(getDomain())
.append(";HttpOnly=").append(isHttpOnly())
.append(";Secure=").append(getSecure())
.append(";SameSite=").append(sameSite);
return sb.toString();
}
public void strict() {
sameSite = SAME_SITE_STRICT;
}
public void laxed() {
sameSite = SAME_SITE_LAX;
}
public static final class CookieBaker {
private final AntiXsrfCookie xsrfCookie;
private CookieBaker(String name, String value) {
xsrfCookie = new AntiXsrfCookie(name, value);
}
public static CookieBaker with(String name, String value) {
return new CookieBaker(name, value);
}
public CookieBaker laxed() {
xsrfCookie.laxed();
return this;
}
public CookieBaker strict() {
xsrfCookie.strict();
return this;
}
public CookieBaker domain(String domain) {
xsrfCookie.setDomain(domain);
return this;
}
public CookieBaker path(String path) {
xsrfCookie.setPath(path);
return this;
}
public CookieBaker maxAge(int maxAge) {
xsrfCookie.setMaxAge(maxAge);
return this;
}
public CookieBaker secure() {
xsrfCookie.setSecure(true);
return this;
}
public CookieBaker insecure() {
xsrfCookie.setSecure(false);
return this;
}
public CookieBaker invisible() {
xsrfCookie.setHttpOnly(true);
return this;
}
public CookieBaker visible() {
xsrfCookie.setHttpOnly(false);
return this;
}
public String build() {
return xsrfCookie.toString();
}
}
}
public class UsageTest {
public static void main(String... args) {
port(8080);
get("/", (request, response) -> {
// Create cookie
AntiXsrfCookie.CookieBaker baker =
AntiXsrfCookie.CookieBaker.with("chocolate_chip", "yummy!")
.secure()
.strict()
.domain("domain.tld")
.invisible()
.path("/")
.maxAge((int) TimeUnit.HOURS.toSeconds(1));
response.header("Set-Cookie", baker.build());
response.type("text/html");
halt(200, "<h1>Done!</h1>");
return response;
});
post("/delete-cookie", (request, response) -> {
AntiXsrfCookie.CookieBaker baker =
AntiXsrfCookie.CookieBaker.with("chocolate_chip", "")
.path("/")
.domain("domain.tld")
.maxAge(-1);
response.header("Set-Cookie", baker.build());
response.type("text/html");
halt(200, "<h1>Cookie is expired. No longer yummy :(</h1>");
return response;
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment