|
|
@@ -130,4 +130,110 @@ describe("createCsrfOriginGuard", () => {
|
|
|
expect(result.allowed).toBe(true);
|
|
|
expect(result.reason).toBe("csrf_guard_bypassed_in_development");
|
|
|
});
|
|
|
+
|
|
|
+ describe("origin-vs-host fallback", () => {
|
|
|
+ it("allows request when origin matches host header (no sec-fetch-site)", () => {
|
|
|
+ const guard = createCsrfOriginGuard({
|
|
|
+ allowedOrigins: [],
|
|
|
+ allowSameOrigin: true,
|
|
|
+ enforceInDevelopment: true,
|
|
|
+ });
|
|
|
+
|
|
|
+ const result = guard.check(
|
|
|
+ createRequest({
|
|
|
+ origin: "http://192.168.1.100:13500",
|
|
|
+ host: "192.168.1.100:13500",
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
+ expect(result).toEqual({ allowed: true });
|
|
|
+ });
|
|
|
+
|
|
|
+ it("allows request when origin matches x-forwarded-host (reverse proxy)", () => {
|
|
|
+ const guard = createCsrfOriginGuard({
|
|
|
+ allowedOrigins: [],
|
|
|
+ allowSameOrigin: true,
|
|
|
+ enforceInDevelopment: true,
|
|
|
+ });
|
|
|
+
|
|
|
+ const result = guard.check(
|
|
|
+ createRequest({
|
|
|
+ origin: "http://myapp.example.com",
|
|
|
+ host: "localhost:13500",
|
|
|
+ "x-forwarded-host": "myapp.example.com",
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
+ expect(result).toEqual({ allowed: true });
|
|
|
+ });
|
|
|
+
|
|
|
+ it("uses first value from comma-separated x-forwarded-host", () => {
|
|
|
+ const guard = createCsrfOriginGuard({
|
|
|
+ allowedOrigins: [],
|
|
|
+ allowSameOrigin: true,
|
|
|
+ enforceInDevelopment: true,
|
|
|
+ });
|
|
|
+
|
|
|
+ const result = guard.check(
|
|
|
+ createRequest({
|
|
|
+ origin: "http://front.example.com",
|
|
|
+ host: "internal:3000",
|
|
|
+ "x-forwarded-host": "front.example.com, proxy.internal",
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
+ expect(result).toEqual({ allowed: true });
|
|
|
+ });
|
|
|
+
|
|
|
+ it("rejects request when origin does not match host", () => {
|
|
|
+ const guard = createCsrfOriginGuard({
|
|
|
+ allowedOrigins: [],
|
|
|
+ allowSameOrigin: true,
|
|
|
+ enforceInDevelopment: true,
|
|
|
+ });
|
|
|
+
|
|
|
+ const result = guard.check(
|
|
|
+ createRequest({
|
|
|
+ origin: "http://evil.example.com",
|
|
|
+ host: "myapp.example.com:13500",
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
+ expect(result.allowed).toBe(false);
|
|
|
+ });
|
|
|
+
|
|
|
+ it("skips host fallback when allowSameOrigin is false", () => {
|
|
|
+ const guard = createCsrfOriginGuard({
|
|
|
+ allowedOrigins: [],
|
|
|
+ allowSameOrigin: false,
|
|
|
+ enforceInDevelopment: true,
|
|
|
+ });
|
|
|
+
|
|
|
+ const result = guard.check(
|
|
|
+ createRequest({
|
|
|
+ origin: "http://192.168.1.100:13500",
|
|
|
+ host: "192.168.1.100:13500",
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
+ expect(result.allowed).toBe(false);
|
|
|
+ });
|
|
|
+
|
|
|
+ it("handles https origin matching host without explicit port", () => {
|
|
|
+ const guard = createCsrfOriginGuard({
|
|
|
+ allowedOrigins: [],
|
|
|
+ allowSameOrigin: true,
|
|
|
+ enforceInDevelopment: true,
|
|
|
+ });
|
|
|
+
|
|
|
+ const result = guard.check(
|
|
|
+ createRequest({
|
|
|
+ origin: "https://example.com",
|
|
|
+ host: "example.com",
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
+ expect(result).toEqual({ allowed: true });
|
|
|
+ });
|
|
|
+ });
|
|
|
});
|