用Wireshark lua编写的协议解析器查看Content-Type为application/x-www-form-urlencoded的HTTP抓包

本文介绍如何使用Lua脚本增强Wireshark的功能,自动解析并展示HTTP POST请求中的application/x-www-form-urlencoded数据,包括参数提取与URL解码。

一、问题:

用Wireshark抓包查看HTTP POST消息,Content-Type为application/x-www-form-urlencoded(对应HTML为<form method="POST">那种提交后的网络包)时不太方便,因为抓包只显示了原始的param1=value1&param2=value2这样的数据,没有把参数提出出来,并对参数进行url decode,如下图所示:

 

二、问题解决过程及心得

Google上没有找到解决方法,最近发现wireshark可以用lua编写解析器,我就试着自己写了一个。过程中走了一些弯路总结一下:

1. 不能用postdissectors,因为HTTP请求有时候是会分几个TCP包的,这种情况下postdissectors只能得到每个包的数据,不能得到完整的application/x-www-form-urlencoded体部内容。

2. 不用自己重新写一个dissector去监听http的tcp端口,这样,你不仅还要调用原来http的dissector,还要自己判断tcp分包了没(reassembled)。

 

刚开始的几种方法都不太理想,最后,看了一下wireshark源码中http解析包的实现,发现只要写一个dissector注册到media_type的dissector table里就可以了。具体的分析请参考《如何在wireshark里用lua脚本编写dissector解析HTTP BODY (after TCP reassembled)》(http://blog.csdn.net/jasonhwang/archive/2010/04/25/5526383.aspx)。

 

 

 

三、如何搞定!!

好,上面的东西大家看不懂没关系只要照下面步骤来一下就搞定了:

1. 在wireshark安装目录(如C:/Program Files/Wireshark)下编写一个文本文件my_form_urlencoded.lua,文件内容如下:

 

 

 

然后修改wireshark安装目录下的init.lua文件:

(1)把disable_lua = true; do return end;这行注释掉:在前面加“--”

(2)然后在init.lua文件最后面加一句:dofile("my_form_urlencoded.lua")

 

OK大功告成,重新打开抓包界面变为如下图:

 

可以看到,原来的Line-based Text...被替换成了行MIME Encapsulation ...。看该节点下[Raw Data]为原始数据,[Decoded Data]下为解开后的一个个参数(经过url decode)。

 

如果要显示原来的Line-based Text...行也可以,到preferences窗口里找到my_form_urlencoded协议,然后选上"Show orignal wireshark's data-text-lines dissection item in Package Details tree"选项即可。

 

 

 

实际上这种方法还可以解析其它媒体类型的HTTP Body,如何编写解析HTTP Body媒体数据的方法请参考《如何在wireshark里用lua脚本编写dissector解析HTTP BODY (after TCP reassembled)》(http://blog.csdn.net/jasonhwang/archive/2010/04/25/5526383.aspx)。

 

 

注:wireshark版本为1.2.7

 

 

2015年 更新:

-- Decode param=value from "application/x-www-form-urlencoded" type http body
-- Author: Huang Qiangxiong (qiangxiong.huang@gmail.com)
-- change log:
--      2010-08-23
--          Place spaces before and after '=' between name and value ( convert '=' to ' = ').
--      2010-04-20
--          Just can play.
--      2010-04-24   
--          Add option "Turn on/off debug tree item" to preference window.
--          Add option "add_orig_item" to preference window.
------------------------------------------------------------------------------------------------
do
    local form_urlencoded_proto = Proto("my_form_urlencoded", "MIME Encapsulation [HQX's plugins]: application/x-www-form-urlencoded")

    --setup options that could be found in preferences->MY_FORM_URLENCODED
    local prefs = form_urlencoded_proto.prefs
    prefs.debug_flag = Pref.bool("Turn on debug (a [DEBUG Tree proto: my_form_urlencoded] item will appear in Package Details tree)", 
                                 false, 
                                 "If you turn of debug, (a [DEBUG Tree proto: my_form_urlencoded] item will appear in Package Details tree)")
    prefs.add_orig_item = Pref.bool("Show orignal wireshark's data-text-lines dissection item in Package Details tree", 
                                    false, 
                                    "Show orignal wireshark's data-text-lines dissection item in Package Details tree")
    -----------DEBUG Function ------------------------------------------------
    --local debug_flag = true
    local dmap = {}
    function d(tree, msg)
        if prefs.debug_flag and tree then
            local dt = dmap[tree]
            if dt == nil then 
                dt = tree:add("[DEBUG Tree for " .. form_urlencoded_proto.name .. "]")
                dmap[tree] = dt
            end
            dt:add("[DEBUG] " .. msg) 
        end
    end
    ---------------------------------------------------------------------------------
    
    ---- url decode (from www.lua.org guide)
    function unescape (s)
        s = string.gsub(s, "+", " ")
        s = string.gsub(s, "%%(%x%x)", function (h)
            return string.char(tonumber(h, 16))
        end)
        return s
    end
   
    ---- save old dissector
    local media_type_table = DissectorTable.get("media_type")
    local old_dissector = media_type_table:get_dissector("application/x-www-form-urlencoded")

    ---- my dissector
    function form_urlencoded_proto.dissector(tvb, pinfo, tree)
        d(tree, "pinfo.curr_proto=" .. pinfo.curr_proto)
        d(tree, "tvb:offset()=" .. tvb:offset()) 
        d(tree, "tvb:len()=" .. tvb:len()) 
        
        if prefs.add_orig_item then
            old_dissector:call(tvb, pinfo, tree)
        end
        
        -- begin build my tree
        local tvb_range = tvb()
        local content = tvb_range:string()
        
        -- add proto item to tree
        local subtree = tree:add(form_urlencoded_proto, tvb_range)
        
        -- add raw data to tree
        subtree:add(tvb_range, "[Raw Data] (" .. tvb_range:len() .. " bytes)"):add(tvb_range, content)

        -- add param value pair to tree
        local pairs_tree = subtree:add(tvb_range, "[Decoded Data]")
        local si = 1
        local ei = 0
        local count = 0
        while ei do
            si = ei + 1
            ei = string.find(content, "&", si)
            local xlen = (ei and (ei - si)) or (content:len() - si + 1)
            if xlen > 0 then
                -- pairs_tree:add(tvb(si-1, xlen), unescape(content:sub(si, si+xlen-1)))
                pairs_tree:add(tvb(si-1, xlen), unescape(content:sub(si, si+xlen-1):gsub("=", " = ", 1)))
                count = count + 1
            end
        end
        pairs_tree:append_text(" (" .. count .. ")")
        
    end

    -- register this dissector
    media_type_table:add("application/x-www-form-urlencoded", form_urlencoded_proto)

end

 

 

 

 

 

 

 

 

 

 

 

 

<think>好的,我现在遇到了在Postman中设置Content-Typeapplication/x-www-form-urlencoded后,数据解码仍然出现空白的问题。我需要仔细分析可能的原因,并找到解决方案。首先,我应该回顾一下x-www-form-urlencoded的基本知识,以确保我的理解正确。 根据引用[1],x-www-form-urlencoded会对非ASCII字符进行URL编码,例如将空格转换为+,而其他特殊字符会被转换为%XX的形式。同时,引用[2]提到,当参数中包含特殊符号时,需要进行转换处理,比如用&连接字段,用+代替空格。因此,如果数据中存在特殊字符没有正确编码,可能会导致服务器端解析错误,从而出现空白值。 接下来,我需要检查Postman中的请求配置是否正确。首先确认Headers中确实设置了Content-Typeapplication/x-www-form-urlencoded。有时候,即使在下拉菜单中选择了这个类型,也可能被其他设置覆盖,需要手动检查Headers列表。 然后,查看Body部分是否选择了x-www-form-urlencoded选项,并且参数是否正确填写。这里需要注意,Postman会自动处理一些编码,但如果参数值中包含保留字符如&、=等,可能需要手动进行URL编码。例如,如果某个参数的值是“a&b”,应该将其编码为“a%26b”,否则服务器可能错误地将其解析为两个参数。 另外,检查是否有隐藏的空格或不可见字符。有时候从其他地方复制粘贴数据时,可能会带入一些不可见的控制字符,这也会导致解析问题。可以尝试手动输入参数,或者使用Postman的“Bulk Edit”功能来清除格式。 还有一个可能性是服务器端的解码问题。即使客户端正确发送了编码后的数据,如果服务器端没有正确处理,比如没有对+号转换为空格,或者没有解码%XX形式的字符,也会导致接收到的数据为空。这时候需要检查服务器端的代码,确认解码逻辑是否正确。 此外,可以尝试在Postman中使用Pre-request Script对参数进行手动编码。例如,使用JavaScript的encodeURIComponent函数对每个值进行编码,确保特殊字符被正确转换。这样即使Postman的自动编码有问题,手动处理也能保证正确性。 如果问题仍然存在,可以尝试将请求导出为cURL命令,在命令行中执行,观察是否有同样的问题。这样可以排除Postman本身的问题,或者查看服务器返回的原始响应,确认数据是否真的被正确发送。 最后,查阅Postman的官方文档或社区,看看是否有已知的bug或配置建议。可能某些版本的Postman存在编码问题,更新到最新版本或许能解决。 总结下来,可能的解决步骤包括:检查Headers设置、手动编码特殊字符、清除隐藏字符、验证服务器端解码、使用Pre-request Script手动编码、导出为cURL测试,以及更新Postman版本。需要逐一排查这些可能性,找出导致数据解码空白的具体原因。</think>在Postman中指定`Content-Type: application/x-www-form-urlencoded`后仍出现数据解码空白的问题,通常与**参数编码格式错误**或**特殊字符未正确处理**有关。以下是具体分析及解决方案: --- ### **一、问题原因分析** 1. **参数未正确编码** - `x-www-form-urlencoded`要求参数值中的特殊字符(如空格、`&`、`=`等)必须进行URL编码[^2]。例如: - 空格需转为`+`或`%20` - `&`需转为`%26` - `=`需转为`%3D` - 若未手动编码,Postman可能未自动处理某些字符,导致服务器解析失败。 2. **Headers冲突或覆盖** - 手动在Headers中添加`Content-Type: application/x-www-form-urlencoded`后,若同时在Body选择其他格式(如`raw`),会导致格式冲突,优先级以Body选项为准。 3. **服务器端解码问题** - 服务器未正确处理`+`或`%XX`格式的字符,导致接收到的值为空。 --- ### **二、解决方案** #### **步骤1:检查Postman配置** 1. **Headers设置** 确保Headers中**没有重复定义**`Content-Type`,且与Body格式一致: ```plaintext Content-Type: application/x-www-form-urlencoded ``` 2. **Body格式选择** 在Body选项卡中选择`x-www-form-urlencoded`,并填写键值对。 **示例:** | Key | Value | |-------|-------------| | name | John+Doe | | email | test%40test.com | - **注意**:`@`需编码为`%40`,空格需用`+`或`%20`代替[^2]。 --- #### **步骤2:手动编码特殊字符** 对包含特殊字符的值进行URL编码: 1. **直接替换字符**(适用于简单场景): - 空格 → `+` - `&` → `%26` - `=` → `%3D` - 中文 → `%E4%B8%AD`(UTF-8编码后) 2. **使用Postman的Pre-request Script自动编码** 在Pre-request Script中添加以下代码,自动编码所有值: ```javascript const postData = { name: "John Doe", message: "Hello & Welcome!" }; Object.keys(postData).forEach(key => { const encodedValue = encodeURIComponent(postData[key]).replace(/%20/g, '+'); pm.environment.set(key, encodedValue); }); ``` 在Body中引用环境变量: | Key | Value | |---------|-------------| | name | {{name}} | | message | {{message}} | --- #### **步骤3:验证服务器端解码逻辑** - **测试用例**:发送已知编码的字符串(如`message=Hello%26World%3D`),检查服务器是否能正确解析为`Hello&World=`。 - **调试工具**:使用Wireshark或浏览器开发者工具抓包,确认实际传输的数据是否符合`x-www-form-urlencoded`格式[^1]。 --- ### **三、常见错误场景** | 场景 | 错误示例 | 正确编码后 | |----------------------|--------------------|--------------------| | 参数含空格 | `name=John Doe` | `name=John+Doe` | | 参数含`&`或`=` | `text=Hello&World` | `text=Hello%26World` | | 参数含中文 | `city=北京` | `city=%E5%8C%97%E4%BA%AC` | --- ### **四、扩展参考** - **编码工具推荐**:使用在线URL编码工具(如[URLEncoder](https://www.urlencoder.org/))快速转换复杂字符。 - **Postman官方文档**:查看[Encoding Parameters](https://learning.postman.com/docs/sending-requests/requests/#encoding-parameters)章节。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值