123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- package waf
- import (
- "fmt"
- "io"
- "net/http"
- "net/url"
- "github.com/crowdsecurity/coraza/v3/experimental"
- "github.com/google/uuid"
- )
- const (
- URIHeaderName = "X-Crowdsec-Waf-Uri"
- VerbHeaderName = "X-Crowdsec-Waf-Verb"
- HostHeaderName = "X-Crowdsec-Waf-Host"
- IPHeaderName = "X-Crowdsec-Waf-Ip"
- )
- // type ResponseRequest struct {
- // UUID string
- // Tx corazatypes.Transaction
- // Interruption *corazatypes.Interruption
- // Err error
- // SendEvents bool
- // }
- // func NewResponseRequest(Tx experimental.FullTransaction, in *corazatypes.Interruption, UUID string, err error) ResponseRequest {
- // return ResponseRequest{
- // UUID: UUID,
- // Tx: Tx,
- // Interruption: in,
- // Err: err,
- // SendEvents: true,
- // }
- // }
- // func (r *ResponseRequest) SetRemediation(remediation string) error {
- // if r.Interruption == nil {
- // return nil
- // }
- // r.Interruption.Action = remediation
- // return nil
- // }
- // func (r *ResponseRequest) SetRemediationByID(ID int, remediation string) error {
- // if r.Interruption == nil {
- // return nil
- // }
- // if r.Interruption.RuleID == ID {
- // r.Interruption.Action = remediation
- // }
- // return nil
- // }
- // func (r *ResponseRequest) CancelEvent() error {
- // // true by default
- // r.SendEvents = false
- // return nil
- // }
- type ParsedRequest struct {
- RemoteAddr string
- Host string
- ClientIP string
- URI string
- Args url.Values
- ClientHost string
- Headers http.Header
- URL *url.URL
- Method string
- Proto string
- Body []byte
- TransferEncoding []string
- UUID string
- Tx experimental.FullTransaction
- ResponseChannel chan WaapTempResponse
- IsInBand bool
- IsOutBand bool
- }
- // Generate a ParsedRequest from a http.Request. ParsedRequest can be consumed by the Waap Engine
- func NewParsedRequestFromRequest(r *http.Request) (ParsedRequest, error) {
- var err error
- body := make([]byte, 0)
- if r.Body != nil {
- body, err = io.ReadAll(r.Body)
- if err != nil {
- return ParsedRequest{}, fmt.Errorf("unable to read body: %s", err)
- }
- }
- // the real source of the request is set in 'x-client-ip'
- clientIP := r.Header.Get(IPHeaderName)
- if clientIP == "" {
- return ParsedRequest{}, fmt.Errorf("Missing '%s' header", IPHeaderName)
- }
- // the real target Host of the request is set in 'x-client-host'
- clientHost := r.Header.Get(HostHeaderName)
- if clientHost == "" {
- return ParsedRequest{}, fmt.Errorf("Missing '%s' header", HostHeaderName)
- }
- // the real URI of the request is set in 'x-client-uri'
- clientURI := r.Header.Get(URIHeaderName)
- if clientURI == "" {
- return ParsedRequest{}, fmt.Errorf("Missing '%s' header", URIHeaderName)
- }
- // the real VERB of the request is set in 'x-client-uri'
- clientMethod := r.Header.Get(VerbHeaderName)
- if clientMethod == "" {
- return ParsedRequest{}, fmt.Errorf("Missing '%s' header", VerbHeaderName)
- }
- // delete those headers before coraza process the request
- delete(r.Header, IPHeaderName)
- delete(r.Header, HostHeaderName)
- delete(r.Header, URIHeaderName)
- delete(r.Header, VerbHeaderName)
- parsedURL, err := url.Parse(clientURI)
- if err != nil {
- return ParsedRequest{}, fmt.Errorf("unable to parse url '%s': %s", clientURI, err)
- }
- return ParsedRequest{
- RemoteAddr: r.RemoteAddr,
- UUID: uuid.New().String(),
- ClientHost: clientHost,
- ClientIP: clientIP,
- URI: parsedURL.Path,
- Method: clientMethod,
- Host: r.Host,
- Headers: r.Header,
- URL: r.URL,
- Proto: r.Proto,
- Body: body,
- Args: parsedURL.Query(), //TODO: Check if there's not potential bypass as it excludes malformed args
- TransferEncoding: r.TransferEncoding,
- ResponseChannel: make(chan WaapTempResponse),
- }, nil
- }
|