public void Inspect(RequestAnalysisContext context, CancellationToken cancellationToken) { if (context.Request.Headers.ContainsKey("X-Scanner")) { context.ReportDiagnostic(new Diagnostic(Rule, Location.RequestHeader("X-Scanner"))); } }
public void Inspect(RequestAnalysisContext context, CancellationToken cancellationToken) { var method = context.Request.Method; if (!HttpMethods.IsGet(method) && !HttpMethods.IsHead(method) && !HttpMethods.IsOptions(method) && !HttpMethods.IsPost(method) && !HttpMethods.IsDelete(method) && !HttpMethods.IsPut(method) && !HttpMethods.IsPatch(method) && !HttpMethods.IsConnect(method) ) { // TRACE must be disabled if (HttpMethods.IsTrace(method)) { context.ReportDiagnostic(new Diagnostic(RuleTrace, Location.Method)); return; } // unknown method context.ReportDiagnostic(new Diagnostic(Rule, Location.Method)); // Apache directory listing exploit if (method.Equals("GETS", StringComparison.OrdinalIgnoreCase)) { context.ReportDiagnostic(new Diagnostic(RuleGets, Location.Method)); } } }
protected void AnalyzeRequest(RequestAnalysisContext context, CancellationToken cancellationToken) { foreach (var inspector in RequestInspectors) { inspector.Inspect(context, cancellationToken); if (context.IsMalicious && Options.Value.Depth == AnalysisDepth.FindFirst) { return; } } }
protected async Task AnalyzeRequestAsync(RequestAnalysisContext context, CancellationToken cancellationToken) { foreach (var inspector in AsyncRequestInspectors) { await inspector.InspectAsync(context, cancellationToken); if (context.IsMalicious && Options.Value.Depth == AnalysisDepth.FindFirst) { return; } } }
public async Task InspectAsync(RequestAnalysisContext context, CancellationToken cancellationToken) { if (context.Request.Method.Equals("post", StringComparison.OrdinalIgnoreCase) && context.Request.HasFormContentType) { bool valid = await Antiforgery.IsRequestValidAsync(context.HttpContext); if (!valid) { context.ReportDiagnostic(new Diagnostic(Rule, Location.RequestBody)); } } }
public void Inspect(RequestAnalysisContext context, CancellationToken cancellationToken) { if (context.Request.Path.Value.Any(Char.IsControl)) { context.ReportDiagnostic(new Diagnostic(Rule, Location.Path)); return; } if (context.Request.QueryString.Value.Any(Char.IsControl)) { context.ReportDiagnostic(new Diagnostic(Rule, Location.QueryString())); return; } foreach (var header in context.Request.Headers.Where(h => h.Key.Any(Char.IsControl) || h.Value.Any(v => v.Any(Char.IsControl)))) { context.ReportDiagnostic(new Diagnostic(Rule, Location.RequestHeader(header.Key))); return; } }
public async Task InvokeAsync(HttpContext context, RequestDelegate next) { var options = Options.Value; context.Request.EnableBuffering(); // analyze request var requestAnalysisContext = new RequestAnalysisContext(context.Request); AnalyzeRequest(requestAnalysisContext, context.RequestAborted); if (requestAnalysisContext.IsMalicious && options.Depth == AnalysisDepth.FindFirst) { await Handle(requestAnalysisContext.Diagnostics); return; } await AnalyzeRequestAsync(requestAnalysisContext, context.RequestAborted); if (requestAnalysisContext.IsMalicious && options.Depth == AnalysisDepth.FindFirst) { await Handle(requestAnalysisContext.Diagnostics); return; } // switch body to buffer var original = context.Response.Body; var buffer = MemoryStreamPool.Get(); context.Response.Body = buffer; var responseAnalysisContext = new ResponseAnalysisContext(context.Response); try { // execute await next(context); // analyze response AnalyzeResponse(responseAnalysisContext, context.RequestAborted); if (responseAnalysisContext.IsMalicious && options.Depth == AnalysisDepth.FindFirst) { await Handle(responseAnalysisContext.Diagnostics); return; } await AnalyzeResponseAsync(responseAnalysisContext, context.RequestAborted); if (responseAnalysisContext.IsMalicious && options.Depth == AnalysisDepth.FindFirst) { await Handle(responseAnalysisContext.Diagnostics); return; } } finally { context.Response.Body = original; } // write response if (responseAnalysisContext.Version != 0) { // remove content-related headers, because may be outdated if (context.Response.Headers.ContainsKey("Content-Encoding")) { context.Response.Headers.Remove("Content-Encoding"); } if (context.Response.Headers.ContainsKey("Content-MD5")) { context.Response.Headers.Remove("Content-MD5"); } // based on body type switch (responseAnalysisContext.SnapshotBodyType) { case ResponseBodyType.String: { var body = responseAnalysisContext.ReadAsString(applyPendingChanges: true); byte[] buffer1 = Encoding.UTF8.GetBytes(body); context.Response.ContentLength = buffer1.Length; context.Response.Headers["Content-Length"] = buffer1.Length.ToString(); await context.Response.Body.WriteAsync(buffer1, 0, buffer1.Length); } break; case ResponseBodyType.Stream: { var body = responseAnalysisContext.ReadAsStream(); context.Response.ContentLength = body.Length; context.Response.Headers["Content-Length"] = body.Length.ToString(); await body.CopyToAsync(context.Response.Body); } break; case ResponseBodyType.ByteArray: { var body = responseAnalysisContext.ReadAsByteArray(); context.Response.ContentLength = body.Length; context.Response.Headers["Content-Length"] = body.Length.ToString(); await context.Response.Body.WriteAsync(body, 0, body.Length); } break; } } else { // write original response if (buffer.Length > 0) { await buffer.Rewind().CopyToAsync(context.Response.Body); } } async Task Handle(IReadOnlyCollection <Diagnostic> diagnostics) { if (diagnostics.Count == 1) { var diagnostic = diagnostics.Single(); Logger.LogWarning($"Request denied. {diagnostic.Rule.Category} ({diagnostic.Rule.Id}) attack found in {diagnostic.Location}: {diagnostic.Rule.Description}."); } else { Logger.LogWarning($"Request denied. Found {diagnostics.Count} diagnostics."); } if (options.Mode == FirewallMode.Prevention) { context.Response.StatusCode = options.DeniedResponseStatusCode; } var settings = new JsonSerializerOptions(); settings.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; settings.WriteIndented = true; var dto = new { diagnostics }; var json = JsonSerializer.Serialize(dto, settings); context.Response.ContentLength = Encoding.UTF8.GetByteCount(json); context.Response.ContentType = "application/json"; await context.Response.WriteAsync(json); } }
public void Inspect(RequestAnalysisContext context, CancellationToken cancellationToken) { var options = Options.CurrentValue; // inspect file extension var file = context.TokenizedPath.LastOrDefault(); if (file != null && file.Contains('.')) { foreach (var found in Extensions.Where(e => file.EndsWith(e.Term, StringComparison.OrdinalIgnoreCase))) { context.ReportDiagnostic(new Diagnostic(Rule.With(found), Location.Path)); if (options.Depth == AnalysisDepth.FindFirst) { return; } } } // inspect directories foreach (var found in Folders.Where(s => context.TokenizedPath.Any(d => d.Equals(s.Term, StringComparison.OrdinalIgnoreCase)))) { context.ReportDiagnostic(new Diagnostic(Rule.With(found), Location.Path)); if (options.Depth == AnalysisDepth.FindFirst) { return; } } // inspect file name if (file != null) { foreach (var found in Files.Where(e => file.Equals(e.Term, StringComparison.OrdinalIgnoreCase))) { context.ReportDiagnostic(new Diagnostic(Rule.With(found), Location.Path)); if (options.Depth == AnalysisDepth.FindFirst) { return; } } } // inspect path var path = context.Request.Path.Value; foreach (var found in RequestBody.Where(i => path.Contains(i.Term, StringComparison.OrdinalIgnoreCase))) { context.ReportDiagnostic(new Diagnostic(Rule.With(found), Location.Path)); if (options.Depth == AnalysisDepth.FindFirst) { return; } } // inspect query string var queryString = context.Request.QueryString.Value; if (!String.IsNullOrEmpty(queryString)) { foreach (var found in RequestBody.Where(i => queryString.Contains(i.Term, StringComparison.OrdinalIgnoreCase))) { context.ReportDiagnostic(new Diagnostic(Rule.With(found), Location.QueryString())); if (options.Depth == AnalysisDepth.FindFirst) { return; } } } // inspect headers foreach (var header in context.Request.Headers) { foreach (var value in header.Value) { foreach (var found in RequestBody.Where(i => value.Contains(i.Term, StringComparison.OrdinalIgnoreCase))) { context.ReportDiagnostic(new Diagnostic(Rule.With(found), Location.RequestHeader(header.Key))); if (options.Depth == AnalysisDepth.FindFirst) { return; } } } } // inspect user agent if (context.Request.Headers.TryGetValue("User-Agent", out var userAgent)) { foreach (var ua in userAgent) { foreach (var found in UserAgents.Where(u => ua.Contains(u.Term, StringComparison.OrdinalIgnoreCase))) { context.ReportDiagnostic(new Diagnostic(Rule.With(found), Location.RequestHeader("User-Agent"))); if (options.Depth == AnalysisDepth.FindFirst) { return; } } } } // inspect headers if (context.Request.HasFormContentType && context.Request.Form != null) { // inspect files foreach (var formFile in context.Request.Form.Files) { var fileName = Path.GetFileName(formFile.FileName); // inspect file extension foreach (var found in FormFileNameExtension.Where(i => fileName.EndsWith(i.Term, StringComparison.OrdinalIgnoreCase))) { context.ReportDiagnostic(new Diagnostic(Rule.With(found), Location.RequestFormFile(formFile.FileName))); if (options.Depth == AnalysisDepth.FindFirst) { return; } } // inspect file name foreach (var found in FormFileName.Where(i => fileName.Equals(i.Term, StringComparison.OrdinalIgnoreCase))) { context.ReportDiagnostic(new Diagnostic(Rule.With(found), Location.RequestFormFile(formFile.FileName))); if (options.Depth == AnalysisDepth.FindFirst) { return; } } } } }