Пример #1
0
 public void Inspect(RequestAnalysisContext context, CancellationToken cancellationToken)
 {
     if (context.Request.Headers.ContainsKey("X-Scanner"))
     {
         context.ReportDiagnostic(new Diagnostic(Rule, Location.RequestHeader("X-Scanner")));
     }
 }
Пример #2
0
        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));
                }
            }
        }
Пример #3
0
 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;
         }
     }
 }
Пример #4
0
        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));
                }
            }
        }
Пример #6
0
        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;
            }
        }
Пример #7
0
        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);
            }
        }
Пример #8
0
        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;
                        }
                    }
                }
            }
        }