mirror of
https://github.com/znc/znc.git
synced 2026-06-11 01:05:05 +02:00
Merge pull request #2016 from MarkLee131/fix/addheader-crlf-guard
HTTPSock: reject CR/LF in AddHeader name/value
This commit is contained in:
@@ -52,6 +52,10 @@ class CHTTPSock : public CSocket {
|
||||
unsigned int uStatusId = 200,
|
||||
const CString& sStatusMsg = "OK");
|
||||
void AddHeader(const CString& sName, const CString& sValue);
|
||||
/** Returns false if `s` contains CR or LF. Used by AddHeader to reject
|
||||
* inputs that could split the response into a separate header or body
|
||||
* (RFC 7230 disallows obs-fold; treat any bare CR/LF as invalid). */
|
||||
static bool IsValidHeaderField(const CString& s);
|
||||
void SetContentType(const CString& sContentType);
|
||||
|
||||
bool PrintNotFound();
|
||||
|
||||
@@ -762,7 +762,17 @@ void CHTTPSock::SetContentType(const CString& sContentType) {
|
||||
m_sContentType = sContentType;
|
||||
}
|
||||
|
||||
bool CHTTPSock::IsValidHeaderField(const CString& s) {
|
||||
return s.find_first_of("\r\n") == CString::npos;
|
||||
}
|
||||
|
||||
void CHTTPSock::AddHeader(const CString& sName, const CString& sValue) {
|
||||
// Reject CR/LF in either half so we never emit a malformed header or
|
||||
// give a caller (e.g. a future module) a cheap response-splitting
|
||||
// primitive. No in-tree caller reaches this with attacker-controlled
|
||||
// bytes today; this is a defensive guard, not a fix for an existing
|
||||
// exploit.
|
||||
if (!IsValidHeaderField(sName) || !IsValidHeaderField(sValue)) return;
|
||||
m_msHeaders[sName] = sValue;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ add_executable(unittest_bin EXCLUDE_FROM_ALL
|
||||
"ThreadTest.cpp" "NickTest.cpp" "ClientTest.cpp" "NetworkTest.cpp"
|
||||
"MessageTest.cpp" "ModulesTest.cpp" "IRCSockTest.cpp" "QueryTest.cpp"
|
||||
"StringTest.cpp" "ConfigTest.cpp" "BufferTest.cpp" "UtilsTest.cpp"
|
||||
"UserTest.cpp" "DebugTest.cpp")
|
||||
"UserTest.cpp" "DebugTest.cpp" "HTTPSockTest.cpp")
|
||||
target_link_libraries(unittest_bin PRIVATE znclib)
|
||||
target_include_directories(unittest_bin PRIVATE
|
||||
"${GTEST_ROOT}" "${GTEST_ROOT}/include"
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2026 ZNC, see the NOTICE file for details.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <znc/HTTPSock.h>
|
||||
|
||||
// Validation contract used by AddHeader to keep CR/LF (and therefore
|
||||
// response-splitting bytes) out of the response stream (#2010).
|
||||
TEST(HTTPSockTest, IsValidHeaderField) {
|
||||
// Plain field names and values are accepted.
|
||||
EXPECT_TRUE(CHTTPSock::IsValidHeaderField(""));
|
||||
EXPECT_TRUE(CHTTPSock::IsValidHeaderField("X-Custom"));
|
||||
EXPECT_TRUE(CHTTPSock::IsValidHeaderField("text/html; charset=utf-8"));
|
||||
EXPECT_TRUE(CHTTPSock::IsValidHeaderField("a value with spaces and tabs\t"));
|
||||
|
||||
// CR or LF anywhere is rejected; both halves of a CRLF pair are
|
||||
// rejected even individually.
|
||||
EXPECT_FALSE(CHTTPSock::IsValidHeaderField("\r"));
|
||||
EXPECT_FALSE(CHTTPSock::IsValidHeaderField("\n"));
|
||||
EXPECT_FALSE(CHTTPSock::IsValidHeaderField("\r\n"));
|
||||
EXPECT_FALSE(CHTTPSock::IsValidHeaderField("X\rFoo"));
|
||||
EXPECT_FALSE(CHTTPSock::IsValidHeaderField("X\nFoo"));
|
||||
EXPECT_FALSE(CHTTPSock::IsValidHeaderField("safe\r\nInjected: yes"));
|
||||
EXPECT_FALSE(CHTTPSock::IsValidHeaderField("trailing\n"));
|
||||
EXPECT_FALSE(CHTTPSock::IsValidHeaderField("\rleading"));
|
||||
}
|
||||
Reference in New Issue
Block a user