ASP.Net MVC:URL请求伪造防范与会话过期后的验证疑问
Great question—this is a super common edge case that many basic request forgery protections overlook! Let’s start by confirming your observation: yes, the validateToken check will absolutely fail when the user’s session expires. Here’s why: the hash was generated using the old, now-invalid Session ID as part of the salt. When the session is gone (or replaced with a new Session ID after re-login), the salt used during validation won’t match what was used to create the hash, so the comparison fails.
Now let’s look at practical fixes you can implement, depending on your use case:
1. Swap Session ID for a persistent user identifier in the salt
Session IDs are temporary by design—they expire, get invalidated, or change on re-login. Instead, use a persistent, unique user identifier (like an encrypted version of the user’s ID) as the core of your salt, paired with a timestamp and a server-side secret key. Here’s how this works:
- When generating the hash: Combine the query string, encrypted user ID, timestamp, and server secret to create the hash.
- When validating: If the user is logged in (even with a new session), fetch their encrypted user ID, recompute the hash using the same formula, and compare it to the one in the URL.
Pseudocode example:
// Generating the hash string encryptedUserId = Encrypt(User.Id.ToString(), ServerSecret); string hash = Sha256Hash(queryString + encryptedUserId + timestamp + ServerSecret); // Validating the hash if (User.IsAuthenticated) { string encryptedUserId = Encrypt(User.Id.ToString(), ServerSecret); string expectedHash = Sha256Hash(queryString + encryptedUserId + timestamp + ServerSecret); return hash.Equals(expectedHash, StringComparison.Ordinal); }
Pros: Eliminates dependency on temporary sessions, making validation stable across logins.
Cons: You need to ensure the encrypted user ID is secure (never use plaintext user IDs) to prevent forgery.
2. Add explicit link expiration + post-login recovery
Keep the timestamp in your hash, but first check it during validation:
- If the timestamp is past your preset expiration window (e.g., 1 hour), immediately return a "Link expired" message—no need to even check the session.
- If the link is still valid but the session is expired: Redirect the user to login, and after successful authentication, automatically re-run the validation using their new session (or better, the persistent user ID from option 1) and execute the original request.
You can even store the original query string and hash in a temporary cache (tied to the user’s IP or browser cookie) during the login flow, so they don’t have to re-click the link.
3. Low-risk operation exemption (use with caution)
If your link triggers a low-risk action (like viewing a report, not modifying data), you can add a narrow exception: If the session is expired but the timestamp is still valid, prompt the user to confirm the action, then allow it without strict session-based hash validation. Only use this for non-sensitive operations—it opens a small security gap, so it’s not ideal for transactions or data changes.
A final best practice: Always use a strong, one-way hash algorithm (like SHA-256) and never expose your server-side secret key to clients.
内容的提问来源于stack exchange,提问作者Monojit Sarkar

