Přeskočit na hlavní obsah

Zpracování chyb

  • Zpracování chyb je součástí celkového zabezpečení aplikace
  • Útok většinou začíná fází průzkumu, kdy se útočník snaží získat co nejvíce informací (verze, frameworky, knihovny)
  • Neošetřené chyby mohou útočníkovi v této fázi výrazně pomoci

Kontext

  • Probémy na úrovni zpracování chyb mohou odhalit mnoho informací o cíli
  • Níže je uveden příklad technologického stacku (Struts2, Tomcat), prostřednictvím výjimky zobrazené uživateli
HTTP Status 500 - For input string: "null"

type Exception report

message For input string: "null"

description The server encountered an internal error that prevented it from fulfilling this request.

exception

java.lang.NumberFormatException: For input string: "null"
java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
java.lang.Integer.parseInt(Integer.java:492)
java.lang.Integer.parseInt(Integer.java:527)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:606)
com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:450)
com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:289)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:252)
org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256)
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
...

note: The full stack trace of the root cause is available in the Apache Tomcat/7.0.56 logs.
  • Níže je uveden příklad odhalení chyby SQL dotazu spolu s cestou k instalaci webu, který lze použít k identifikaci místa injektáže
Warning: odbc_fetch_array() expects parameter /1 to be resource, boolean given
in D:\app\index_new.php on line 188
  • V některých případech je efektivnější definovat error handler jako součást kódu
  • Pokud dojde k neočekávané chybě, aplikace vždy vrátí obecnou odpověď, ale podrobnosti jsou zaznamenány pouze na straně serveru za účelem dalšího prošetření

Generická odpověď

  • Aplikace by se měla snažit pokrýt všechny způsoby selhání a používat chyby 5xx pouze k označení odpovědí na požadavky, které nemůže splnit
  • Aplikace by neměla poskytovat žádný obsah v odpovědi, který by odhalil podrobnosti o implementaci
  • Aplikace by měla vhodně logovat a monitorovat

Návrh

Webová aplikace v Javě

  1. Nakonfigurujte globální error handler na úrovni deskriptoru nasazení web.xml
  • Následující konfiguraci je možné použít od specifikace Servlet 2.5 a vyšší
  • Jakákoli neočekávaná chyba při této konfiguraci způsobí přesměrování na error.jsp, kde bude chyba zalogována a vrácena bude obecná odpověď
  • web.xml konfigurace
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
...
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/error.jsp</location>
</error-page>
...
</web-app>
  • Obsah souboru error.jsp
<%@ page language="java" isErrorPage="true" contentType="application/json; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String errorMessage = exception.getMessage();
// Log the exception via the content of the implicit variable named "exception"
// ...
// We build a generic response with a JSON format because we are in a REST API app context
// We also add an HTTP response header to indicate to the client app that the response is an error
response.setHeader("X-ERROR", "true");
// Note that we're using an internal server error response
// In some cases it may be prudent to return 4xx error codes, when we have misbehaving clients
response.setStatus(500);
%>
{"message":"An error occur, please retry"}

Java SpringMVC / SpringBoot aplikace

  • Pomocí SpringMVC nebo SpringBoot je možné definovat globální error handler tak, že se do projektu implementuje následující třída
import net.minidev.json.JSONObject;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;

/**
* Global error handler in charge of returning a generic response in case of unexpected error situation.
*/
@ControllerAdvice
public class RestResponseEntityExceptionHandler {

@ExceptionHandler(value = {Exception.class})
public ResponseEntity<Object> handleGlobalError(RuntimeException exception, WebRequest request) {
// Log the exception via the content of the parameter named "exception"
// ...
// We build a generic response with a JSON format because we are in a REST API app context
// We also add an HTTP response header to indicate to the client app that the response is an error
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setContentType(MediaType.APPLICATION_JSON);
responseHeaders.set("X-ERROR", "true");
JSONObject responseBody = new JSONObject();
responseBody.put("message", "An error occur, please retry");
// Note that we're using an internal server error response
// In some cases it may be prudent to return 4xx error codes, if we have misbehaving clients
ResponseEntity<JSONObject> response = new ResponseEntity<>(responseBody, responseHeaders,
HttpStatus.INTERNAL_SERVER_ERROR);
return (ResponseEntity) response;
}
}

Webová aplikace ASP NET Core

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Net;

namespace MyProject.Controllers
{
/// <summary>
/// API Controller used to intercept and handle all unexpected exception
/// </summary>
[Route("api/[controller]")]
[ApiController]
[AllowAnonymous]
public class ErrorController : ControllerBase
{
/// <summary>
/// Action that will be invoked for any call to this Controller in order to handle the current error
/// </summary>
/// <returns>A generic error formatted as JSON because we are in a REST API app context</returns>
[HttpGet]
[HttpPost]
[HttpHead]
[HttpDelete]
[HttpPut]
[HttpOptions]
[HttpPatch]
public JsonResult Handle()
{
// Get the exception that has implied the call to this controller
Exception exception = HttpContext.Features.Get<IExceptionHandlerFeature>()?.Error;
// Log the exception via the content of the variable named "exception" if it is not NULL
// ...
// We build a generic response with a JSON format because we are in a REST API app context
// We also add an HTTP response header to indicate to the client app that the response
// is an error
var responseBody = new Dictionary<String, String>{ {
"message", "An error occur, please retry"
} };
JsonResult response = new JsonResult(responseBody);
// Note that we're using an internal server error response
// In some cases it may be prudent to return 4xx error codes, if we have misbehaving clients
response.StatusCode = (int)HttpStatusCode.InternalServerError;
Request.HttpContext.Response.Headers.Remove("X-ERROR");
Request.HttpContext.Response.Headers.Add("X-ERROR", "true");
return response;
}
}
}
  • Definice mapování chyb na API controller pro zpracování výjimek v souboru Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace MyProject
{
public class Startup
{
...
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// First we configure the error handler middleware!
// We enable the global error handler in others environments than DEV
// because debug page are useful during implementation
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// Our global handler is defined on "/api/error" URL so we indicate to the
// exception handler to call this API controller
// on any unexpected exception raised by the application
app.UseExceptionHandler("/api/error");

// To customize the response content type and text, use the overload of
// UseStatusCodePages that takes a content type and format string.
app.UseStatusCodePages("text/plain", "Status code page, status code: {0}");
}

// We configure others middlewares, remember that the declaration order is important...
app.UseMvc();
// ...
}
}
}

ASP NET Web API

  • Pomocí tohoto rozhraní je možné definovat a registrovat obslužné programy
  • Díky tomu je možné sledovat a zpracovávat všechny chyby, které se v aplikaci vyskytnou
  • Definice obslužného programu pro sledování podrobností o chybě
using System;
using System.Web.Http.ExceptionHandling;

namespace MyProject.Security
{
/// <summary>
/// Global logger used to trace any error that occurs at application wide level
/// </summary>
public class GlobalErrorLogger : ExceptionLogger
{
/// <summary>
/// Method in charge of the management of the error from a tracing point of view
/// </summary>
/// <param name="context">Context containing the error details</param>
public override void Log(ExceptionLoggerContext context)
{
// Get the exception
Exception exception = context.Exception;
// Log the exception via the content of the variable named "exception" if it is not NULL
// ...
}
}
}
  • Definice obsluhy pro správu chyby s cílem vrátit obecnou odpověď
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.ExceptionHandling;

namespace MyProject.Security
{
/// <summary>
/// Global handler used to handle any error that occurs at application wide level
/// </summary>
public class GlobalErrorHandler : ExceptionHandler
{
/// <summary>
/// Method in charge of handle the generic response send in case of error
/// </summary>
/// <param name="context">Error context</param>
public override void Handle(ExceptionHandlerContext context)
{
context.Result = new GenericResult();
}

/// <summary>
/// Class used to represent the generic response send
/// </summary>
private class GenericResult : IHttpActionResult
{
/// <summary>
/// Method in charge of creating the generic response
/// </summary>
/// <param name="cancellationToken">Object to cancel the task</param>
/// <returns>A task in charge of sending the generic response</returns>
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
// We build a generic response with a JSON format because we are in a REST API app context
// We also add an HTTP response header to indicate to the client app that the response
// is an error
var responseBody = new Dictionary<String, String>{ {
"message", "An error occur, please retry"
} };
// Note that we're using an internal server error response
// In some cases it may be prudent to return 4xx error codes, if we have misbehaving clients
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.InternalServerError);
response.Headers.Add("X-ERROR", "true");
response.Content = new StringContent(JsonConvert.SerializeObject(responseBody),
Encoding.UTF8, "application/json");
return Task.FromResult(response);
}
}
}
}
  • Registrace obou obslužných rutin v souboru WebApiConfig.cs
using MyProject.Security;
using System.Web.Http;
using System.Web.Http.ExceptionHandling;

namespace MyProject
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Register global error logging and handling handlers in first
config.Services.Replace(typeof(IExceptionLogger), new GlobalErrorLogger());
config.Services.Replace(typeof(IExceptionHandler), new GlobalErrorHandler());
// Rest of the configuration
// ...
}
}
}
  • Nastavení sekce customErrors do souboru Web.config:
<configuration>
...
<system.web>
<customErrors mode="RemoteOnly"
defaultRedirect="~/ErrorPages/Oops.aspx" />
...
</system.web>
</configuration>
  • Zdrojový kód všech příkladů najdete na GitHubu
  • HTTP chyby jsou definovány v RFC 2616

Kam dál

Zranitelnosti

Cheat sheety

Checklisty