mirror of
				https://github.com/aler9/rtsp-simple-server
				synced 2025-10-31 19:13:22 +08:00 
			
		
		
		
	webrtc, hls: prevent brute-force attacks by waiting before sending responses (#2100)
	
		
			
	
		
	
	
		
	
		
			Some checks reported warnings
		
		
	
	
		
			
				
	
				lint / code (push) Has been cancelled
				
					
					
				
			
		
			
				
	
				lint / mod-tidy (push) Has been cancelled
				
					
					
				
			
		
			
				
	
				lint / apidocs (push) Has been cancelled
				
					
					
				
			
		
			
				
	
				test / test64 (push) Has been cancelled
				
					
					
				
			
		
			
				
	
				test / test32 (push) Has been cancelled
				
					
					
				
			
		
			
				
	
				test / test_highlevel (push) Has been cancelled
				
					
					
				
			
		
		
	
	
				
					
				
			
		
			Some checks reported warnings
		
		
	
	lint / code (push) Has been cancelled
				lint / mod-tidy (push) Has been cancelled
				lint / apidocs (push) Has been cancelled
				test / test64 (push) Has been cancelled
				test / test32 (push) Has been cancelled
				test / test_highlevel (push) Has been cancelled
				This commit is contained in:
		| @@ -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 | ||||||
| 		} | 		} | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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, | ||||||
|   | |||||||
| @@ -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 | ||||||
| 			} | 			} | ||||||
|   | |||||||
| @@ -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) | ||||||
|   | |||||||
| @@ -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 | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Alessandro Ros
					Alessandro Ros