Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/dotnet-api/antissrfhandler.md
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
2 changes: 1 addition & 1 deletion docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
8 changes: 4 additions & 4 deletions dotnet/FunctionalTests/AntiSSRFPolicy.AddXFFHeaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
15 changes: 10 additions & 5 deletions dotnet/FunctionalTests/AntiSSRFPolicy.AddressTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,16 @@ public async Task CheckDefaults_IMDSAsync()
}

var mappedIpUrl = "https://[::ffff:169.254.169.254]/latest/meta-data/";
await Assert.ThrowsAsync<AntiSSRFException>(() => client.GetAsync(mappedIpUrl, new CancellationTokenSource(TimeSpan.FromSeconds(1)).Token));
await Assert.ThrowsAsync<AntiSSRFException>(() => client2.GetAsync(mappedIpUrl, new CancellationTokenSource(TimeSpan.FromSeconds(1)).Token));
await Assert.ThrowsAsync<AntiSSRFException>(() => client3.GetAsync(mappedIpUrl, new CancellationTokenSource(TimeSpan.FromSeconds(1)).Token));
using (var cts5 = new CancellationTokenSource(TimeSpan.FromSeconds(1)))
await Assert.ThrowsAsync<AntiSSRFException>(() => client.GetAsync(mappedIpUrl, cts5.Token));
using (var cts6 = new CancellationTokenSource(TimeSpan.FromSeconds(1)))
await Assert.ThrowsAsync<AntiSSRFException>(() => client2.GetAsync(mappedIpUrl, cts6.Token));
using (var cts7 = new CancellationTokenSource(TimeSpan.FromSeconds(1)))
await Assert.ThrowsAsync<AntiSSRFException>(() => 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)
{
Expand Down Expand Up @@ -283,7 +287,8 @@ public async Task CheckDefaults_WireServerAsync()
await Assert.ThrowsAsync<AntiSSRFException>(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)
{
Expand Down
8 changes: 4 additions & 4 deletions dotnet/FunctionalTests/AntiSSRFPolicy.HeaderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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");
Expand All @@ -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");
Expand Down
4 changes: 2 additions & 2 deletions dotnet/FunctionalTests/AntiSSRFPolicy.SchemeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public void CheckDefaults()
}

[Fact]
public async Task OnTrue()
public async Task OnFalse()
{
AntiSSRFPolicy policy = new(PolicyConfigOptions.None)
{
Expand All @@ -45,7 +45,7 @@ public async Task OnTrue()
}

[Fact]
public async Task OnFalse()
public async Task OnTrue()
{
var policy = new AntiSSRFPolicy(PolicyConfigOptions.None)
{
Expand Down
2 changes: 1 addition & 1 deletion nodejs/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ export default tseslint.config({
eslint: eslint
},
rules: {
"func-style": ["error", "declaration"]
"func-style": ["error", "declaration", { "allowArrowFunctions": true }]
}
});
2 changes: 1 addition & 1 deletion nodejs/package.json
Original file line number Diff line number Diff line change
@@ -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": [
Expand Down
15 changes: 13 additions & 2 deletions nodejs/tests/UnitTests/AntiSSRFPolicy.AddXFFHeader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand Down
Loading