From 0b36ba5cea5683447483e404d60b8ad9aeab58b8 Mon Sep 17 00:00:00 2001 From: nnposter Date: Sat, 29 Apr 2017 14:05:57 +0000 Subject: [PATCH] Allows unquoted cookie values to contain whitespace, as defined in RFC 6265. Fixes #844 --- CHANGELOG | 3 +++ nselib/http.lua | 28 ++++++++++------------------ 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 24e30daebb..788f8e8224 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -24,6 +24,9 @@ o [NSE] The HTTP response object has a new member, fragment, which contains a partially received body (if any) when the overall request fails to complete. [nnposter] +o [NSE][GH#844] NSE now correctly parses a Set-Cookie header that has unquoted + whitespace in the cookie value (which is allowed per RFC 6265). [nnposter] + o [NSE][GH#731] NSE is now able to process HTTP responses with a Set-Cookie header that has an extraneous trailing semicolon. [nnposter] diff --git a/nselib/http.lua b/nselib/http.lua index 01df1e9280..4560912b0c 100644 --- a/nselib/http.lua +++ b/nselib/http.lua @@ -751,9 +751,8 @@ end -- -- Every key except "name" and "value" is optional. -- --- This function attempts to support the cookie syntax defined in RFC 2109 --- along with the backwards-compatibility suggestions from its section 10, --- "HISTORICAL". Values need not be quoted, but if they start with a quote they +-- This function attempts to support the header parser defined in RFC 6265, +-- Section 5.2. Values need not be quoted, but if they start with a quote they -- will be interpreted as a quoted string. parse_set_cookie = function (s) local name, value @@ -762,27 +761,22 @@ parse_set_cookie = function (s) local cookie = {} -- Get the NAME=VALUE part. - local pos = skip_space(s, 1) - pos, cookie.name = get_token(s, pos) - if not cookie.name then + local pos + _, pos, cookie.name = s:find("^[ \t]*(.-)[ \t]*=[ \t]*") + if not (cookie.name or ""):find("^[^;]+$") then return nil, "Can't get cookie name." end - pos = skip_space(s, pos) - if s:sub(pos, pos) ~= "=" then - return nil, string.format("Expected '=' after cookie name \"%s\".", cookie.name) - end pos = pos + 1 - pos = skip_space(s, pos) if s:sub(pos, pos) == "\"" then pos, cookie.value = get_quoted_string(s, pos) + if not cookie.value then + return nil, string.format("Can't get value of cookie named \"%s\".", cookie.name) + end + pos = skip_space(s, pos) else - _, pos, cookie.value = s:find("([^; \t]*)", pos) + _, pos, cookie.value = s:find("^(.-)[ \t]*%f[;\0]", pos) pos = pos + 1 end - if not cookie.value then - return nil, string.format("Can't get value of cookie named \"%s\".", cookie.name) - end - pos = skip_space(s, pos) -- Loop over the attributes. while s:sub(pos, pos) == ";" do @@ -2893,7 +2887,6 @@ test_suite = unittest.TestSuite:new() do local cookie_tests = { ---[[ Uncomment after #844 is merged { -- #844 " SESSIONID=IgAAABjN8b3xxxNsLRIiSpHLPn1lE=&IgAAAxxxMT6Bw==&Huawei USG6320&langfrombrows=en-US©right=2014;secure", { name = "SESSIONID", @@ -2901,7 +2894,6 @@ do secure = true } }, ---]] { -- #866 " SID=c98fefa3ad659caa20b89582419bb14f; Max-Age=1200; Version=1", { name = "SID",