CARVIEW |
Select Language
HTTP/2 200
date: Tue, 29 Jul 2025 06:23:11 GMT
content-type: text/html; charset=utf-8
vary: X-PJAX, X-PJAX-Container, Turbo-Visit, Turbo-Frame, X-Requested-With,Accept-Encoding, Accept, X-Requested-With
etag: W/"3d0081bc757fb8ff176e2183592fa805"
cache-control: max-age=0, private, must-revalidate
strict-transport-security: max-age=31536000; includeSubdomains; preload
x-frame-options: deny
x-content-type-options: nosniff
x-xss-protection: 0
referrer-policy: origin-when-cross-origin, strict-origin-when-cross-origin
content-security-policy: default-src 'none'; base-uri 'self'; child-src github.githubassets.com github.com/assets-cdn/worker/ github.com/assets/ gist.github.com/assets-cdn/worker/; connect-src 'self' uploads.github.com www.githubstatus.com collector.github.com raw.githubusercontent.com api.github.com github-cloud.s3.amazonaws.com github-production-repository-file-5c1aeb.s3.amazonaws.com github-production-upload-manifest-file-7fdce7.s3.amazonaws.com github-production-user-asset-6210df.s3.amazonaws.com *.rel.tunnels.api.visualstudio.com wss://*.rel.tunnels.api.visualstudio.com objects-origin.githubusercontent.com copilot-proxy.githubusercontent.com proxy.individual.githubcopilot.com proxy.business.githubcopilot.com proxy.enterprise.githubcopilot.com *.actions.githubusercontent.com wss://*.actions.githubusercontent.com productionresultssa0.blob.core.windows.net/ productionresultssa1.blob.core.windows.net/ productionresultssa2.blob.core.windows.net/ productionresultssa3.blob.core.windows.net/ productionresultssa4.blob.core.windows.net/ productionresultssa5.blob.core.windows.net/ productionresultssa6.blob.core.windows.net/ productionresultssa7.blob.core.windows.net/ productionresultssa8.blob.core.windows.net/ productionresultssa9.blob.core.windows.net/ productionresultssa10.blob.core.windows.net/ productionresultssa11.blob.core.windows.net/ productionresultssa12.blob.core.windows.net/ productionresultssa13.blob.core.windows.net/ productionresultssa14.blob.core.windows.net/ productionresultssa15.blob.core.windows.net/ productionresultssa16.blob.core.windows.net/ productionresultssa17.blob.core.windows.net/ productionresultssa18.blob.core.windows.net/ productionresultssa19.blob.core.windows.net/ github-production-repository-image-32fea6.s3.amazonaws.com github-production-release-asset-2e65be.s3.amazonaws.com insights.github.com wss://alive.github.com api.githubcopilot.com api.individual.githubcopilot.com api.business.githubcopilot.com api.enterprise.githubcopilot.com; font-src github.githubassets.com; form-action 'self' github.com gist.github.com copilot-workspace.githubnext.com objects-origin.githubusercontent.com; frame-ancestors 'none'; frame-src viewscreen.githubusercontent.com notebooks.githubusercontent.com; img-src 'self' data: blob: github.githubassets.com media.githubusercontent.com camo.githubusercontent.com identicons.github.com avatars.githubusercontent.com private-avatars.githubusercontent.com github-cloud.s3.amazonaws.com objects.githubusercontent.com release-assets.githubusercontent.com secured-user-images.githubusercontent.com/ user-images.githubusercontent.com/ private-user-images.githubusercontent.com opengraph.githubassets.com copilotprodattachments.blob.core.windows.net/github-production-copilot-attachments/ github-production-user-asset-6210df.s3.amazonaws.com customer-stories-feed.github.com spotlights-feed.github.com objects-origin.githubusercontent.com *.githubusercontent.com; manifest-src 'self'; media-src github.com user-images.githubusercontent.com/ secured-user-images.githubusercontent.com/ private-user-images.githubusercontent.com github-production-user-asset-6210df.s3.amazonaws.com gist.github.com; script-src github.githubassets.com; style-src 'unsafe-inline' github.githubassets.com; upgrade-insecure-requests; worker-src github.githubassets.com github.com/assets-cdn/worker/ github.com/assets/ gist.github.com/assets-cdn/worker/
server: github.com
content-encoding: gzip
accept-ranges: bytes
set-cookie: _gh_sess=JDwH9oNdpwekvWT8XL1PA9YS2BWjHyDL%2FCkL6qJXQ5l37ygkPh%2FbBFPmcWq3sdR1OUKtP3RTkz%2Bu%2Bt214CI5Ln%2FJsegHb0n1W50VtzKBDtZkbaueGYMx7o%2FKfsheoVb2ePTtZw6P8FkswfC63IybpBYAEmV1PHkV3vIHZSChsPV4F7AlmvAt58uHh4eeFDp%2BdxXMdV%2F17Gt0odIP7R8I52CGiag0lngf3yCCJgBsh0NY%2B87phhdt6o2uJp6cKCUgA8cmKqXYple2YKMZ9s6NAw%3D%3D--IOEeW6cQJYVhBulx--qsA2BXgjjCE5cjKBxjUg6A%3D%3D; Path=/; HttpOnly; Secure; SameSite=Lax
set-cookie: _octo=GH1.1.761205335.1753770191; Path=/; Domain=github.com; Expires=Wed, 29 Jul 2026 06:23:11 GMT; Secure; SameSite=Lax
set-cookie: logged_in=no; Path=/; Domain=github.com; Expires=Wed, 29 Jul 2026 06:23:11 GMT; HttpOnly; Secure; SameSite=Lax
x-github-request-id: A3AE:17B9D8:46330D:5BAE21:688868CF
useragent-blocking · GitHub
Show Gist options
Save gistlyn/7e8f54b662a4037c698ccbab71abd709 to your computer and use it in GitHub Desktop.
{{ message }}
Instantly share code, notes, and snippets.
Created
April 11, 2025 06:33
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
Save gistlyn/7e8f54b662a4037c698ccbab71abd709 to your computer and use it in GitHub Desktop.
useragent-blocking
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.Extensions.Options; | |
namespace MyApp; | |
/// <summary> | |
/// Options for configuring the UserAgentBlockingMiddleware | |
/// </summary> | |
public class UserAgentBlockingOptions | |
{ | |
/// <summary> | |
/// List of user agents to block (supports exact matches or substring matches) | |
/// </summary> | |
public List<string> BlockedUserAgents { get; set; } = new(); | |
/// <summary> | |
/// HTTP status code to return when a user agent is blocked (defaults to 403 Forbidden) | |
/// </summary> | |
public int BlockedStatusCode { get; set; } = StatusCodes.Status403Forbidden; | |
/// <summary> | |
/// Optional message to return in the response body when a user agent is blocked | |
/// </summary> | |
public string BlockedMessage { get; set; } = "Access denied based on your user agent"; | |
/// <summary> | |
/// If true, will perform case-insensitive matching (defaults to true) | |
/// </summary> | |
public bool IgnoreCase { get; set; } = true; | |
/// <summary> | |
/// If true, blocked requests will be logged (defaults to true) | |
/// </summary> | |
public bool LogBlockedRequests { get; set; } = true; | |
} | |
/// <summary> | |
/// Middleware that blocks requests from specific user agents | |
/// </summary> | |
public class UserAgentBlockingMiddleware( | |
RequestDelegate next, | |
IOptions<UserAgentBlockingOptions> options, | |
ILogger<UserAgentBlockingMiddleware> logger) | |
{ | |
UserAgentBlockingOptions Options => options?.Value ?? throw new ArgumentNullException(nameof(options)); | |
public async Task InvokeAsync(HttpContext context) | |
{ | |
if (context == null) | |
{ | |
throw new ArgumentNullException(nameof(context)); | |
} | |
// Get the User-Agent header | |
string userAgent = context.Request.Headers["User-Agent"].ToString(); | |
// Check if the user agent should be blocked | |
if (ShouldBlockUserAgent(userAgent)) | |
{ | |
// Log the blocked request if enabled | |
if (Options.LogBlockedRequests) | |
{ | |
logger.LogInformation( | |
"Request blocked from user agent: {UserAgent}, IP: {IPAddress}, Path: {Path}", | |
userAgent, | |
context.Connection.RemoteIpAddress, | |
context.Request.Path); | |
} | |
// Set the response status code | |
context.Response.StatusCode = Options.BlockedStatusCode; | |
context.Response.ContentType = "text/plain"; | |
// Write the blocked message to the response | |
await context.Response.WriteAsync(Options.BlockedMessage); | |
return; | |
} | |
// If not blocked, continue to the next middleware | |
await next(context); | |
} | |
private bool ShouldBlockUserAgent(string userAgent) | |
{ | |
if (string.IsNullOrEmpty(userAgent)) | |
{ | |
// You might want to block requests with no user agent | |
// Return true here if you want to block empty user agents | |
return false; | |
} | |
foreach (var blockedAgent in Options.BlockedUserAgents) | |
{ | |
var comparison = Options.IgnoreCase | |
? StringComparison.OrdinalIgnoreCase | |
: StringComparison.Ordinal; | |
if (userAgent.Contains(blockedAgent, comparison)) | |
return true; | |
if (blockedAgent.Contains(' ') && userAgent.Contains(blockedAgent.Replace(" ",""), comparison)) | |
return true; | |
} | |
return false; | |
} | |
} | |
/// <summary> | |
/// Extension methods for registering the UserAgentBlockingMiddleware | |
/// </summary> | |
public static class UserAgentBlockingMiddlewareExtensions | |
{ | |
/// <summary> | |
/// Adds the UserAgentBlockingMiddleware to the application pipeline | |
/// </summary> | |
public static IApplicationBuilder UseUserAgentBlocking( | |
this IApplicationBuilder builder) | |
{ | |
return builder.UseMiddleware<UserAgentBlockingMiddleware>(); | |
} | |
/// <summary> | |
/// Adds the UserAgentBlockingMiddleware to the application pipeline with custom options | |
/// </summary> | |
public static IApplicationBuilder UseUserAgentBlocking( | |
this IApplicationBuilder builder, | |
Action<UserAgentBlockingOptions> configureOptions) | |
{ | |
// Create a new options instance | |
var options = new UserAgentBlockingOptions(); | |
// Apply the configuration | |
configureOptions(options); | |
// Use the middleware with the configured options | |
return builder.UseMiddleware<UserAgentBlockingMiddleware>(Options.Create(options)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You can’t perform that action at this time.