@@ -2,6 +2,7 @@ import type { Context, MiddlewareHandler, Next } from "hono";
22import { getCookie } from "hono/cookie" ;
33import type { HonoContext } from "../../types/env" ;
44import { RateLimitError } from "./errors" ;
5+ import { validateSession } from "./session" ;
56
67interface RateLimitConfig {
78 /** Wranglerで設定したRate Limiting binding名 */
@@ -10,8 +11,8 @@ interface RateLimitConfig {
1011 limit : number ;
1112 /** ウィンドウサイズ(秒) */
1213 period : 10 | 60 ;
13- /** キー生成関数(デフォルト: セッションID 、未認証時はIPアドレス) */
14- keyGenerator ?: ( c : Context < HonoContext > ) => string ;
14+ /** キー生成関数(デフォルト: 検証済みユーザーID 、未認証時はIPアドレス) */
15+ keyGenerator ?: ( c : Context < HonoContext > ) => string | Promise < string > ;
1516}
1617
1718/**
@@ -22,7 +23,8 @@ export function rateLimiter(config: RateLimitConfig): MiddlewareHandler<HonoCont
2223
2324 return async ( c : Context < HonoContext > , next : Next ) => {
2425 const rateLimit = c . env [ binding ] ;
25- const { success } = await rateLimit . limit ( { key : keyGenerator ( c ) } ) ;
26+ const key = await keyGenerator ( c ) ;
27+ const { success } = await rateLimit . limit ( { key } ) ;
2628
2729 c . header ( "X-RateLimit-Limit" , String ( limit ) ) ;
2830
@@ -37,11 +39,20 @@ export function rateLimiter(config: RateLimitConfig): MiddlewareHandler<HonoCont
3739
3840/**
3941 * デフォルトのキー生成関数
42+ *
43+ * session_idクッキーはクライアントが自由に設定できるため、
44+ * 生の値をキーに使うとレート制限を回避できてしまう。
45+ * 必ずKVで検証し、検証済みのユーザーIDのみをキーに採用する。
4046 */
41- function defaultKeyGenerator ( c : Context < HonoContext > ) : string {
47+ async function defaultKeyGenerator ( c : Context < HonoContext > ) : Promise < string > {
4248 const sessionId = getCookie ( c , "session_id" ) ;
4349 if ( sessionId ) {
44- return `session:${ sessionId } ` ;
50+ try {
51+ const userId = await validateSession ( c . env . KV , sessionId ) ;
52+ return `user:${ userId } ` ;
53+ } catch {
54+ // 無効・期限切れのセッションはIPアドレスにフォールバック
55+ }
4556 }
4657
4758 const ip =
@@ -56,7 +67,7 @@ function defaultKeyGenerator(c: Context<HonoContext>): string {
5667/**
5768 * 認証済みユーザーのキー生成関数
5869 */
59- function authenticatedUserKeyGenerator ( c : Context < HonoContext > ) : string {
70+ async function authenticatedUserKeyGenerator ( c : Context < HonoContext > ) : Promise < string > {
6071 const userId = c . get ( "userId" ) ;
6172 return userId ? `user:${ userId } ` : defaultKeyGenerator ( c ) ;
6273}
0 commit comments