diff --git a/docs/dotnet-api/antissrfhandler.md b/docs/dotnet-api/antissrfhandler.md index fd7ab78..376b72e 100644 --- a/docs/dotnet-api/antissrfhandler.md +++ b/docs/dotnet-api/antissrfhandler.md @@ -8,11 +8,11 @@ description: "HttpMessageHandler that enforces AntiSSRF policies" # AntiSSRFHandler -`AntiSSRFHandler` is the type of the object returned from `AntiSSRFPolicy.GetHandler`. The `AntiSSRFHandler` wraps `HttpClientHandler` or `HttpSocketsHandler` and implements `HttpMessageHandler` while exposing some properties on the inner handler. This handler performs DNS resolution validation, scheme enforcement, header checks, and redirect following according to the configured policy. +`AntiSSRFHandler` is the type of the object returned from `AntiSSRFPolicy.GetHandler`. The `AntiSSRFHandler` wraps `HttpClientHandler` or `SocketsHttpHandler` and implements `HttpMessageHandler` while exposing some properties on the inner handler. This handler performs DNS resolution validation, scheme enforcement, header checks, and redirect following according to the configured policy. ### .NET Core -In .NET Core, the inner handler is an `HttpSocketsHandler`. The exposed properties below can be used exactly as they are used in the original `HttpSocketsHandler` type. Please see [HttpSocketsHandler](https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpsocketshandler) for details. +In .NET Core, the inner handler is a `SocketsHttpHandler`. The exposed properties below can be used exactly as they are used in the original `SocketsHttpHandler` type. Please see [SocketsHttpHandler](https://docs.microsoft.com/en-us/dotnet/api/system.net.http.socketshandler) for details. ```csharp - public bool AllowAutoRedirect { get; set; } diff --git a/docs/getting-started.md b/docs/getting-started.md index f168e61..9cf3312 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -100,7 +100,7 @@ The AntiSSRF library provides validation for different scenarios based on your t 4. **Stay up-to-date** - Keep the library updated to receive the latest security changes. Instead of using `PolicyConfigOptions.ExternalV1`, consider using `PolicyConfigOptions.ExternalOnlyLatest`. + Keep the library updated to receive the latest security changes. Instead of using `PolicyConfigOptions.ExternalOnlyV1`, consider using `PolicyConfigOptions.ExternalOnlyLatest`. ## Next Steps diff --git a/docs/index.md b/docs/index.md index c699d16..6ca0fb3 100644 --- a/docs/index.md +++ b/docs/index.md @@ -56,7 +56,7 @@ AntiSSRF helps mitigate these risks by: ### Learn More -- � **Getting Started**: [Installation and Quick Start Guide](getting-started) +- 🚀 **Getting Started**: [Installation and Quick Start Guide](getting-started) - 📖 **API Documentation**: [.NET API](dotnet-api) \| [Node.js API](nodejs-api) - ❓ **Common Questions**: [FAQ](faq) diff --git a/dotnet/FunctionalTests/AntiSSRFPolicy.AddXFFHeaderTests.cs b/dotnet/FunctionalTests/AntiSSRFPolicy.AddXFFHeaderTests.cs index cc9f82c..c3038dc 100644 --- a/dotnet/FunctionalTests/AntiSSRFPolicy.AddXFFHeaderTests.cs +++ b/dotnet/FunctionalTests/AntiSSRFPolicy.AddXFFHeaderTests.cs @@ -36,7 +36,7 @@ public async Task OnTrue() { AddXFFHeader = true }; - HttpClient client = new(policy.GetHandler()); + using var client = new HttpClient(policy.GetHandler()); var response = await client.GetAsync($"https://{TestDomain}/api/header-check?header=X-Forwarded-For", CancellationToken.None); Assert.Equal(HttpStatusCode.OK, response.StatusCode); @@ -49,12 +49,12 @@ public async Task DoesNotOverwriteHeader() { AddXFFHeader = true }; - HttpClient client = new(policy.GetHandler()); + using var client = new HttpClient(policy.GetHandler()); - var request = new HttpRequestMessage(HttpMethod.Get, $"https://{TestDomain}/api/header-check?header=X-Forwarded-For"); + using var request = new HttpRequestMessage(HttpMethod.Get, $"https://{TestDomain}/api/header-check?header=X-Forwarded-For"); request.Headers.Add("X-Forwarded-For", "1.2.3.4"); - var response = await client.SendAsync(request, CancellationToken.None); + using var response = await client.SendAsync(request, CancellationToken.None); Assert.Equal(HttpStatusCode.OK, response.StatusCode); var contents = await response.Content.ReadAsStringAsync(); Assert.Contains("1.2.3.4", contents); diff --git a/dotnet/FunctionalTests/AntiSSRFPolicy.AddressTests.cs b/dotnet/FunctionalTests/AntiSSRFPolicy.AddressTests.cs index 4312aef..a936f03 100644 --- a/dotnet/FunctionalTests/AntiSSRFPolicy.AddressTests.cs +++ b/dotnet/FunctionalTests/AntiSSRFPolicy.AddressTests.cs @@ -159,12 +159,16 @@ public async Task CheckDefaults_IMDSAsync() } var mappedIpUrl = "https://[::ffff:169.254.169.254]/latest/meta-data/"; - await Assert.ThrowsAsync(() => client.GetAsync(mappedIpUrl, new CancellationTokenSource(TimeSpan.FromSeconds(1)).Token)); - await Assert.ThrowsAsync(() => client2.GetAsync(mappedIpUrl, new CancellationTokenSource(TimeSpan.FromSeconds(1)).Token)); - await Assert.ThrowsAsync(() => client3.GetAsync(mappedIpUrl, new CancellationTokenSource(TimeSpan.FromSeconds(1)).Token)); + using (var cts5 = new CancellationTokenSource(TimeSpan.FromSeconds(1))) + await Assert.ThrowsAsync(() => client.GetAsync(mappedIpUrl, cts5.Token)); + using (var cts6 = new CancellationTokenSource(TimeSpan.FromSeconds(1))) + await Assert.ThrowsAsync(() => client2.GetAsync(mappedIpUrl, cts6.Token)); + using (var cts7 = new CancellationTokenSource(TimeSpan.FromSeconds(1))) + await Assert.ThrowsAsync(() => client3.GetAsync(mappedIpUrl, cts7.Token)); try { - await client4.GetAsync(mappedIpUrl, new CancellationTokenSource(TimeSpan.FromSeconds(1)).Token); + using (var cts8 = new CancellationTokenSource(TimeSpan.FromSeconds(1))) + await client4.GetAsync(mappedIpUrl, cts8.Token); } catch (Exception ex) when (ex is not AntiSSRFException) { @@ -283,7 +287,8 @@ public async Task CheckDefaults_WireServerAsync() await Assert.ThrowsAsync(async () => await client3.GetAsync(ipUrl, new CancellationTokenSource(TimeSpan.FromSeconds(1)).Token)); try { - await client4.GetAsync(ipUrl, new CancellationTokenSource(TimeSpan.FromSeconds(1)).Token); + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1)); + await client4.GetAsync(ipUrl, cts.Token); } catch (Exception ex) when (ex is not AntiSSRFException) { diff --git a/dotnet/FunctionalTests/AntiSSRFPolicy.HeaderTests.cs b/dotnet/FunctionalTests/AntiSSRFPolicy.HeaderTests.cs index f54ec3a..8f4035d 100755 --- a/dotnet/FunctionalTests/AntiSSRFPolicy.HeaderTests.cs +++ b/dotnet/FunctionalTests/AntiSSRFPolicy.HeaderTests.cs @@ -71,7 +71,7 @@ public async Task RequiredHeader() { AntiSSRFPolicy policy = new(PolicyConfigOptions.None); policy.AddRequiredHeaders(["X-Test-Header"]); - HttpClient client = new(policy.GetHandler()); + using HttpClient client = new(policy.GetHandler()); string Url = $"https://{TestDomain}/api/header-check?header=X-Test-Header"; using HttpRequestMessage request = new(HttpMethod.Get, Url); @@ -89,7 +89,7 @@ public async Task DeniedHeader() { AntiSSRFPolicy policy = new(PolicyConfigOptions.None); policy.AddDeniedHeaders(["X-Test-Header"]); - HttpClient client = new(policy.GetHandler()); + using HttpClient client = new(policy.GetHandler()); string url = $"https://{TestDomain}/"; using HttpRequestMessage request = new(HttpMethod.Get, url); @@ -109,7 +109,7 @@ public async Task Headers_AreCaseInsensitive() AntiSSRFPolicy requiredPolicy = new(PolicyConfigOptions.None); requiredPolicy.AddRequiredHeaders(["X-Test-Header"]); - HttpClient requiredClient = new(requiredPolicy.GetHandler()); + using HttpClient requiredClient = new(requiredPolicy.GetHandler()); using HttpRequestMessage requiredRequest = new(HttpMethod.Get, url); requiredRequest.Headers.Add("x-test-header", "test-value"); @@ -118,7 +118,7 @@ public async Task Headers_AreCaseInsensitive() AntiSSRFPolicy deniedPolicy = new(PolicyConfigOptions.None); deniedPolicy.AddDeniedHeaders(["X-Test-Header"]); - HttpClient deniedClient = new(deniedPolicy.GetHandler()); + using HttpClient deniedClient = new(deniedPolicy.GetHandler()); using HttpRequestMessage deniedRequest = new(HttpMethod.Get, $"https://{TestDomain}/"); deniedRequest.Headers.Add("x-test-header", "test-value"); diff --git a/dotnet/FunctionalTests/AntiSSRFPolicy.SchemeTests.cs b/dotnet/FunctionalTests/AntiSSRFPolicy.SchemeTests.cs index 55623db..662501b 100644 --- a/dotnet/FunctionalTests/AntiSSRFPolicy.SchemeTests.cs +++ b/dotnet/FunctionalTests/AntiSSRFPolicy.SchemeTests.cs @@ -30,7 +30,7 @@ public void CheckDefaults() } [Fact] - public async Task OnTrue() + public async Task OnFalse() { AntiSSRFPolicy policy = new(PolicyConfigOptions.None) { @@ -45,7 +45,7 @@ public async Task OnTrue() } [Fact] - public async Task OnFalse() + public async Task OnTrue() { var policy = new AntiSSRFPolicy(PolicyConfigOptions.None) { diff --git a/nodejs/eslint.config.mjs b/nodejs/eslint.config.mjs index 93e71e0..83b9c4c 100644 --- a/nodejs/eslint.config.mjs +++ b/nodejs/eslint.config.mjs @@ -15,6 +15,6 @@ export default tseslint.config({ eslint: eslint }, rules: { - "func-style": ["error", "declaration"] + "func-style": ["error", "declaration", { "allowArrowFunctions": true }] } }); diff --git a/nodejs/package.json b/nodejs/package.json index d6f8957..ec64620 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -1,7 +1,7 @@ { "name": "@microsoft/antissrf", "version": "1.0.0", - "description": "A library to prevent SSRF vulnerbilities in Node.js applications", + "description": "A library to prevent SSRF vulnerabilities in Node.js applications", "main": "./out/src/index.js", "types": "./out/src/index.d.ts", "files": [ diff --git a/nodejs/tests/UnitTests/AntiSSRFPolicy.AddXFFHeader.test.ts b/nodejs/tests/UnitTests/AntiSSRFPolicy.AddXFFHeader.test.ts index 5b9feba..d92b390 100644 --- a/nodejs/tests/UnitTests/AntiSSRFPolicy.AddXFFHeader.test.ts +++ b/nodejs/tests/UnitTests/AntiSSRFPolicy.AddXFFHeader.test.ts @@ -19,16 +19,27 @@ describe("AntiSSRFPolicy AddXFFHeader Tests", () => { it("on true", async () => { const policy = new AntiSSRFPolicy(PolicyConfigOptions.None); policy.addXFFHeader = true; + const instance = axios.create({ + httpAgent: policy.getHttpAgent(), + httpsAgent: policy.getHttpsAgent(), + validateStatus: () => true + }); - const res = await axios.get(`https://${TEST_DOMAIN}/api/header-check?header=X-Forwarded-For`); + const res = await instance.get(`https://${TEST_DOMAIN}/api/header-check?header=X-Forwarded-For`); assert.strictEqual(res.status, 200); + assert.ok(res.data.headerValue, "Expected server to observe the X-Forwarded-For header added by policy"); }); it("does not overwrite header", async () => { const policy = new AntiSSRFPolicy(PolicyConfigOptions.None); policy.addXFFHeader = true; + const instance = axios.create({ + httpAgent: policy.getHttpAgent(), + httpsAgent: policy.getHttpsAgent(), + validateStatus: () => true + }); - const res = await axios.get(`https://${TEST_DOMAIN}/api/header-check?header=X-Forwarded-For`, { + const res = await instance.get(`https://${TEST_DOMAIN}/api/header-check?header=X-Forwarded-For`, { headers: { "X-Forwarded-For": "1.2.3.4" }