Browse Source

webrtc, hls: prevent brute-force attacks by waiting before sending responses (#2100)

pull/2106/head
Alessandro Ros 3 years ago committed by GitHub
parent
commit
1fa53b49d4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      internal/core/hls_http_server.go
  2. 6
      internal/core/rtmp_conn.go
  3. 4
      internal/core/rtsp_conn.go
  4. 5
      internal/core/webrtc_http_server.go
  5. 1
      internal/core/webrtc_manager.go
  6. 9
      internal/core/webrtc_session.go

9
internal/core/hls_http_server.go

@ -7,6 +7,7 @@ import (
"net/http" "net/http"
gopath "path" gopath "path"
"strings" "strings"
"time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -14,6 +15,10 @@ import (
"github.com/bluenviron/mediamtx/internal/logger" "github.com/bluenviron/mediamtx/internal/logger"
) )
const (
hlsPauseAfterAuthError = 2 * time.Second
)
//go:embed hls_index.html //go:embed hls_index.html
var hlsIndex []byte var hlsIndex []byte
@ -166,6 +171,10 @@ func (s *hlsHTTPServer) onRequest(ctx *gin.Context) {
remoteAddr := net.JoinHostPort(ip, port) remoteAddr := net.JoinHostPort(ip, port)
s.Log(logger.Info, "connection %v failed to authenticate: %v", remoteAddr, terr.message) s.Log(logger.Info, "connection %v failed to authenticate: %v", remoteAddr, terr.message)
// wait some seconds to stop brute force attacks
<-time.After(hlsPauseAfterAuthError)
ctx.Writer.WriteHeader(http.StatusUnauthorized) ctx.Writer.WriteHeader(http.StatusUnauthorized)
return return
} }

6
internal/core/rtmp_conn.go

@ -30,7 +30,7 @@ import (
) )
const ( const (
rtmpConnPauseAfterAuthError = 2 * time.Second rtmpPauseAfterAuthError = 2 * time.Second
) )
func pathNameAndQuery(inURL *url.URL) (string, url.Values, string) { func pathNameAndQuery(inURL *url.URL) (string, url.Values, string) {
@ -367,7 +367,7 @@ func (c *rtmpConn) runRead(ctx context.Context, u *url.URL) error {
if res.err != nil { if res.err != nil {
if terr, ok := res.err.(*errAuthentication); ok { if terr, ok := res.err.(*errAuthentication); ok {
// wait some seconds to stop brute force attacks // wait some seconds to stop brute force attacks
<-time.After(rtmpConnPauseAfterAuthError) <-time.After(rtmpPauseAfterAuthError)
return terr return terr
} }
return res.err return res.err
@ -782,7 +782,7 @@ func (c *rtmpConn) runPublish(u *url.URL) error {
if res.err != nil { if res.err != nil {
if terr, ok := res.err.(*errAuthentication); ok { if terr, ok := res.err.(*errAuthentication); ok {
// wait some seconds to stop brute force attacks // wait some seconds to stop brute force attacks
<-time.After(rtmpConnPauseAfterAuthError) <-time.After(rtmpPauseAfterAuthError)
return terr return terr
} }
return res.err return res.err

4
internal/core/rtsp_conn.go

@ -17,7 +17,7 @@ import (
) )
const ( const (
rtspConnPauseAfterAuthError = 2 * time.Second rtspPauseAfterAuthError = 2 * time.Second
) )
type rtspConnParent interface { type rtspConnParent interface {
@ -204,7 +204,7 @@ func (c *rtspConn) handleAuthError(authErr error) (*base.Response, error) {
} }
// wait some seconds to stop brute force attacks // wait some seconds to stop brute force attacks
<-time.After(rtspConnPauseAfterAuthError) <-time.After(rtspPauseAfterAuthError)
return &base.Response{ return &base.Response{
StatusCode: base.StatusUnauthorized, StatusCode: base.StatusUnauthorized,

5
internal/core/webrtc_http_server.go

@ -10,6 +10,7 @@ import (
"regexp" "regexp"
"strconv" "strconv"
"strings" "strings"
"time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/google/uuid" "github.com/google/uuid"
@ -318,6 +319,10 @@ func (s *webRTCHTTPServer) onRequest(ctx *gin.Context) {
} }
s.Log(logger.Info, "connection %v failed to authenticate: %v", remoteAddr, terr.message) s.Log(logger.Info, "connection %v failed to authenticate: %v", remoteAddr, terr.message)
// wait some seconds to stop brute force attacks
<-time.After(webrtcPauseAfterAuthError)
ctx.Writer.WriteHeader(http.StatusUnauthorized) ctx.Writer.WriteHeader(http.StatusUnauthorized)
return return
} }

1
internal/core/webrtc_manager.go

@ -23,6 +23,7 @@ import (
) )
const ( const (
webrtcPauseAfterAuthError = 2 * time.Second
webrtcHandshakeTimeout = 10 * time.Second webrtcHandshakeTimeout = 10 * time.Second
webrtcTrackGatherTimeout = 2 * time.Second webrtcTrackGatherTimeout = 2 * time.Second
webrtcPayloadMaxSize = 1188 // 1200 - 12 (RTP header) webrtcPayloadMaxSize = 1188 // 1200 - 12 (RTP header)

9
internal/core/webrtc_session.go

@ -240,8 +240,12 @@ func (s *webRTCSession) runPublish() (int, error) {
}) })
if res.err != nil { if res.err != nil {
if _, ok := res.err.(*errAuthentication); ok { if _, ok := res.err.(*errAuthentication); ok {
// wait some seconds to stop brute force attacks
<-time.After(webrtcPauseAfterAuthError)
return http.StatusUnauthorized, res.err return http.StatusUnauthorized, res.err
} }
return http.StatusBadRequest, res.err return http.StatusBadRequest, res.err
} }
@ -363,11 +367,16 @@ func (s *webRTCSession) runRead() (int, error) {
}) })
if res.err != nil { if res.err != nil {
if _, ok := res.err.(*errAuthentication); ok { if _, ok := res.err.(*errAuthentication); ok {
// wait some seconds to stop brute force attacks
<-time.After(webrtcPauseAfterAuthError)
return http.StatusUnauthorized, res.err return http.StatusUnauthorized, res.err
} }
if strings.HasPrefix(res.err.Error(), "no one is publishing") { if strings.HasPrefix(res.err.Error(), "no one is publishing") {
return http.StatusNotFound, res.err return http.StatusNotFound, res.err
} }
return http.StatusBadRequest, res.err return http.StatusBadRequest, res.err
} }

Loading…
Cancel
Save