php session fixation,聊聊session fixation attacks

本文主要讲一下session fixation attacks以及spring security对它的防范。

session fixation attacks

会话固定攻击,是利用那些登录前和登录之后sessionId没有变化的漏洞来获取登录态,进而获取用户的相关信息等。

servlet3.1规范

servlet3.1规范中,HttpServletRequest.java明确规定了一个changeSessionId的方法

tomcat-embed-core-8.5.23-sources.jar!/javax/servlet/http/HttpServletRequest.java

/**

* Changes the session ID of the session associated with this request. This

* method does not create a new session object it only changes the ID of the

* current session.

*

* @return the new session ID allocated to the session

* @see HttpSessionIdListener

* @since Servlet 3.1

*/

public String changeSessionId();

SessionAuthenticationStrategy

spring-security-web-4.2.3.RELEASE-sources.jar!/org/springframework/security/web/authentication/session/SessionAuthenticationStrategy.java

/**

* Allows pluggable support for HttpSession-related behaviour when an authentication

* occurs.

*

* Typical use would be to make sure a session exists or to change the session Id to guard

* against session-fixation attacks.

*

* @author Luke Taylor

* @since

*/

public interface SessionAuthenticationStrategy {

/**

* Performs Http session-related functionality when a new authentication occurs.

*

* @throws SessionAuthenticationException if it is decided that the authentication is

* not allowed for the session. This will typically be because the user has too many

* sessions open at once.

*/

void onAuthentication(Authentication authentication, HttpServletRequest request,

HttpServletResponse response) throws SessionAuthenticationException;

}

spring security 提供了SessionAuthenticationStrategy接口,用来在登陆成功之后的处理session相关逻辑,它有个抽象类AbstractSessionFixationProtectionStrategy

AbstractSessionFixationProtectionStrategy

spring-security-web-4.2.3.RELEASE-sources.jar!/org/springframework/security/web/authentication/session/AbstractSessionFixationProtectionStrategy.java

/**

* Called when a user is newly authenticated.

*

* If a session already exists, and matches the session Id from the client, a new

* session will be created, and the session attributes copied to it (if

* {@code migrateSessionAttributes} is set). If the client's requested session Id is

* invalid, nothing will be done, since there is no need to change the session Id if

* it doesn't match the current session.

*

* If there is no session, no action is taken unless the {@code alwaysCreateSession}

* property is set, in which case a session will be created if one doesn't already

* exist.

*/

public void onAuthentication(Authentication authentication,

HttpServletRequest request, HttpServletResponse response) {

boolean hadSessionAlready = request.getSession(false) != null;

if (!hadSessionAlready && !alwaysCreateSession) {

// Session fixation isn't a problem if there's no session

return;

}

// Create new session if necessary

HttpSession session = request.getSession();

if (hadSessionAlready && request.isRequestedSessionIdValid()) {

String originalSessionId;

String newSessionId;

Object mutex = WebUtils.getSessionMutex(session);

synchronized (mutex) {

// We need to migrate to a new session

originalSessionId = session.getId();

session = applySessionFixation(request);

newSessionId = session.getId();

}

if (originalSessionId.equals(newSessionId)) {

logger.warn("Your servlet container did not change the session ID when a new session was created. You will"

+ " not be adequately protected against session-fixation attacks");

}

onSessionChange(originalSessionId, session, authentication);

}

}

如果是servlet3.1的话,则spring security默认的SessionAuthenticationStrategy就是ChangeSessionIdAuthenticationStrategy

SessionManagementConfigurer

spring-security-config-4.2.3.RELEASE-sources.jar!/org/springframework/security/config/annotation/web/configurers/SessionManagementConfigurer.java

/**

* Creates the default {@link SessionAuthenticationStrategy} for session fixation

* @return the default {@link SessionAuthenticationStrategy} for session fixation

*/

private static SessionAuthenticationStrategy createDefaultSessionFixationProtectionStrategy() {

try {

return new ChangeSessionIdAuthenticationStrategy();

}

catch (IllegalStateException e) {

return new SessionFixationProtectionStrategy();

}

}

ChangeSessionIdAuthenticationStrategy

spring-security-web-4.2.3.RELEASE-sources.jar!/org/springframework/security/web/authentication/session/ChangeSessionIdAuthenticationStrategy.java

/**

* Uses {@code HttpServletRequest.changeSessionId()} to protect against session fixation

* attacks. This is the default implementation for Servlet 3.1+.

*

* @author Rob Winch

* @since 3.2

*/

public final class ChangeSessionIdAuthenticationStrategy

extends AbstractSessionFixationProtectionStrategy {

private final Method changeSessionIdMethod;

public ChangeSessionIdAuthenticationStrategy() {

Method changeSessionIdMethod = ReflectionUtils

.findMethod(HttpServletRequest.class, "changeSessionId");

if (changeSessionIdMethod == null) {

throw new IllegalStateException(

"HttpServletRequest.changeSessionId is undefined. Are you using a Servlet 3.1+ environment?");

}

this.changeSessionIdMethod = changeSessionIdMethod;

}

/*

* (non-Javadoc)

*

* @see org.springframework.security.web.authentication.session.

* AbstractSessionFixationProtectionStrategy

* #applySessionFixation(javax.servlet.http.HttpServletRequest)

*/

@Override

HttpSession applySessionFixation(HttpServletRequest request) {

ReflectionUtils.invokeMethod(this.changeSessionIdMethod, request);

return request.getSession();

}

}

通过反射调用changeSessionId方法,具体是调用Request#changeSessionId

Request#changeSessionId

tomcat-embed-core-8.5.23-sources.jar!/org/apache/catalina/connector/Request.java

/**

* Changes the session ID of the session associated with this request.

*

* @return the old session ID before it was changed

* @see javax.servlet.http.HttpSessionIdListener

* @since Servlet 3.1

*/

@Override

public String changeSessionId() {

Session session = this.getSessionInternal(false);

if (session == null) {

throw new IllegalStateException(

sm.getString("coyoteRequest.changeSessionId"));

}

Manager manager = this.getContext().getManager();

manager.changeSessionId(session);

String newSessionId = session.getId();

this.changeSessionId(newSessionId);

return newSessionId;

}

这里调用了manager.changeSessionId(session)

ManagerBase#changeSessionId(session)

tomcat-embed-core-8.5.23-sources.jar!/org/apache/catalina/session/ManagerBase.java

@Override

public void changeSessionId(Session session) {

String newId = generateSessionId();

changeSessionId(session, newId, true, true);

}

protected void changeSessionId(Session session, String newId,

boolean notifySessionListeners, boolean notifyContainerListeners) {

String oldId = session.getIdInternal();

session.setId(newId, false);

session.tellChangedSessionId(newId, oldId,

notifySessionListeners, notifyContainerListeners);

}

/**

* Generate and return a new session identifier.

* @return a new session id

*/

protected String generateSessionId() {

String result = null;

do {

if (result != null) {

// Not thread-safe but if one of multiple increments is lost

// that is not a big deal since the fact that there was any

// duplicate is a much bigger issue.

duplicates++;

}

result = sessionIdGenerator.generateSessionId();

} while (sessions.containsKey(result));

return result;

}

StandardSessionIdGenerator#generateSessionId

tomcat-embed-core-8.5.23-sources.jar!/org/apache/catalina/util/StandardSessionIdGenerator.java

public class StandardSessionIdGenerator extends SessionIdGeneratorBase {

@Override

public String generateSessionId(String route) {

byte random[] = new byte[16];

int sessionIdLength = getSessionIdLength();

// Render the result as a String of hexadecimal digits

// Start with enough space for sessionIdLength and medium route size

StringBuilder buffer = new StringBuilder(2 * sessionIdLength + 20);

int resultLenBytes = 0;

while (resultLenBytes < sessionIdLength) {

getRandomBytes(random);

for (int j = 0;

j < random.length && resultLenBytes < sessionIdLength;

j++) {

byte b1 = (byte) ((random[j] & 0xf0) >> 4);

byte b2 = (byte) (random[j] & 0x0f);

if (b1 < 10)

buffer.append((char) ('0' + b1));

else

buffer.append((char) ('A' + (b1 - 10)));

if (b2 < 10)

buffer.append((char) ('0' + b2));

else

buffer.append((char) ('A' + (b2 - 10)));

resultLenBytes++;

}

}

if (route != null && route.length() > 0) {

buffer.append('.').append(route);

} else {

String jvmRoute = getJvmRoute();

if (jvmRoute != null && jvmRoute.length() > 0) {

buffer.append('.').append(jvmRoute);

}

}

return buffer.toString();

}

}

这段是tomcat生成sessionId的逻辑

小结

spring security通过SessionAuthenticationStrategy,在登录成功之后进行相关session处理,如果servlet3.1+,则使用ChangeSessionIdAuthenticationStrategy来更换sessionId,以防范session fixation attacks。

doc

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值