Fix path traversal, auth-bypass, and DoS findings from the security review
- Add ValidateFileName (allowlist regex, rejects .. and separators) and apply it to every route that concatenates a raw path segment into a filesystem or remote FTP path: /show/lvgmc-forecast, /show/grib, /grib/binary-chunk, and /debug/file. Previously an unauthenticated caller could read arbitrary files, including /proc/self/environ (leaks LVGMC_PASSWORD/POSTGRES_PASSWORD). - Harden ValidateInt to reject negative integers. - Gate /api/fetch/lvgmc/stations behind ENABLE_LVGMC_FTP_JOBS so it can no longer trigger a real, unauthenticated FTP login regardless of the flag; stop leaking error.getMessage in its response. - Add an explicit /api/* catch-all (NotFound) so an unmatched API route can never fall through to the SPA fallback and be served index.html as a 200. - Cap binary-chunk read length at 64MB to prevent an unbounded allocation.
This commit is contained in:
@@ -81,7 +81,16 @@ class DataService(log: Logger[IO]) {
|
||||
Executors.newFixedThreadPool(8) // limit concurrency
|
||||
)
|
||||
|
||||
private val MAX_BINARY_CHUNK_BYTES = 64 * 1024 * 1024
|
||||
|
||||
def getBinaryChunk(offset: Int, length: Int, fileName: String): IO[Array[Byte]] = {
|
||||
if (length > MAX_BINARY_CHUNK_BYTES || length < 0)
|
||||
IO.raiseError(new IllegalArgumentException(s"Requested length $length is invalid (max $MAX_BINARY_CHUNK_BYTES bytes)"))
|
||||
else
|
||||
getBinaryChunkUnchecked(offset, length, fileName)
|
||||
}
|
||||
|
||||
private def getBinaryChunkUnchecked(offset: Int, length: Int, fileName: String): IO[Array[Byte]] = {
|
||||
val fileResource = Resource.make(
|
||||
IO.blocking(new RandomAccessFile(s"$GRIB_FOLDER/$fileName", "r"))
|
||||
)(file => IO.blocking(file.close()))
|
||||
|
||||
Reference in New Issue
Block a user