前端页面如下:(index.html)

<!DOCTYPE>
<html><head><title>Upload File Test</title></head><body><form enctype='multipart/form-data' action="/cgi-bin/LocalVideoUpload" method="post"><input type="file" name='pics' multiple><input type="file" name='another_pic'><input type="submit"></form ></body>
</html>

从中可以看到,使用了一个表单作为上传内容,其中enctype属性表明这个表单在上传的时候使用multipart/form-data格式。表单中有两个输入框,在浏览器里会显示为【选择文件】。其中pics可以选择多个文件上传,another_pic只能选择一个文件上传。

那么什么是multipart/form-data格式呢?

首先根据标准文档和搜索到的资料,这是一种Content-Type,而且是建立于POST请求方式基础上的。其本身意味着整个表单数据编码为一条消息,每个控件的数据对应消息的一部分。

先用Wireshark抓一下包,这里要注意的是,由于wireshark没法抓localhost环回的包,因此我在本地的另一个设备上设置了一个代理,这样请求会经过该设备的中转,从而能够被wireshark捕获到。当然也有更好的办法,比如配置路由,安装rawpacp等等.... 可以参考 这个博客

抓到的包大概是这样:

这里用了wireshark的过滤条件:ip.src eq 192.168.31.102 and ip.dst eq 192.168.31.51 and ip.proto eq TCP,这样能够筛选出从102机器发往51机器的所有TCP报文,沿着SYN查找带有PSH,ACK的报文(其中PSH表示push操作位,意味着发送方希望接收方立刻处理数据,具体参见 这个博客 ,在截图中还可以看到很多TCP segment of a reassembled PDU这样的提示,这表明TCP报文经过了分片,可以参考 这个博客。关于更多的wireshark过滤条件语法,参见 这个博客)然后右键报文——追踪TCP流,就会弹出来这样一个窗口:

这里就可以看到报文的格式了。在Content-Type中,multipart/form-data被指定,随后跟着一个boundary参数顾名思义就是消息的边界分隔符。在POST的正文中可以看到,每个消息以--{$boundary}开始。最后一个消息后附带一个--{$boundary}--表示结束。整个POST的正文长度(包括一大堆的分隔符和内部消息头)为Content-Length。

这样,在CGI中,接收到CONTENT_TYPE和CONTENT_LENGTH参数后,分析是不是multipart/form-data,如果是就提取出来boundary,读取post内容,根据boundary分割输入数据,解析内部请求头。(此处代码较多,就不贴了)

需要注意的是,如果CGI运行在Windows下,而且上传的文件中包含二进制数据,此时需要将标准输入流设置成二进制模式,具体参见 这个博客。

有关内部消息头中的Content-Disposition,可以参考 这里。另外Content-Disposition还可以被用在响应头中,用于下载文件,具体参考 这个博客。

由于内部消息头没有Content-Length,因此没有办法预知这一部分有多少数据,只能不断读入然后判断是否遇到了边界。

需要小心的是,内部消息头指出的filename可能是经过精心编辑的带有类似 ../ 的路径,如果直接使用有可能会覆盖其他文件,从而为攻击提供了可乘之机。

这里再介绍一种能够显示上传进度的前端页面写法:(摘自 这个博客)

<!DOCTYPE html>
<html>
<head><title>Upload Files using XMLHttpRequest - Minimal</title><script type="text/javascript">function fileSelected() {var file = document.getElementById('fileToUpload').files[0];if (file) {var fileSize = 0;if (file.size > 1024 * 1024)fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB';elsefileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';document.getElementById('fileName').innerHTML = 'Name: ' + file.name;document.getElementById('fileSize').innerHTML = 'Size: ' + fileSize;document.getElementById('fileType').innerHTML = 'Type: ' + file.type;}}function uploadFile() {var fd = new FormData();fd.append("fileToUpload", document.getElementById('fileToUpload').files[0]);var xhr = new XMLHttpRequest();xhr.upload.addEventListener("progress", uploadProgress, false);xhr.addEventListener("load", uploadComplete, false);xhr.addEventListener("error", uploadFailed, false);xhr.addEventListener("abort", uploadCanceled, false);xhr.open("POST", "/cgi-bin/LocalVideoUpload");//修改成自己的接口xhr.send(fd);}function uploadProgress(evt) {if (evt.lengthComputable) {var percentComplete = Math.round(evt.loaded * 100 / evt.total);document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%';}else {document.getElementById('progressNumber').innerHTML = 'unable to compute';}}function uploadComplete(evt) {/* 服务器端返回响应时候触发event事件*/alert(evt.target.responseText);}function uploadFailed(evt) {alert("There was an error attempting to upload the file.");}function uploadCanceled(evt) {alert("The upload has been canceled by the user or the browser dropped the connection.");}</script>
</head>
<body><form id="form1" enctype="multipart/form-data" method="post"><div class="row"><label for="fileToUpload">Select a File to Upload</label><br /><input type="file" name="fileToUpload" id="fileToUpload" onchange="fileSelected();"/></div><div id="fileName"></div><div id="fileSize"></div><div id="fileType"></div><div class="row"><input type="button" onclick="uploadFile()" value="Upload" /></div><div id="progressNumber"></div></form>
</body>
</html>

此外,还可以使用libcurl库和winhttp库来直接对cgi发起上传文件的POST请求,可以参考 这个博客。

POST上传数据的时候,除了multipart/form-data外,还有默认的application/x-www-from-urlencoded类型,这种类型会将数据转化为键值对key=value&key2=value2这样的,同时还会对数据进行编码(不适合文件上传)。还有raw类型,其Content-Type为text/plain或者application/json,text/html这样的。其内容不会被修改。有关更多的Content-Type内容,可以参考 这个博客。除此之外还有一种binary类型,其Content-Type为application/octet-stream,由于没有分隔符,因此只能上传一个文件。

C/C++ CGI处理文件上传相关推荐

  1. c语言实现cgi之文件上传和下载

    作者 QQ群:852283276 微信:arm80x86 微信公众号:青儿创客基地 B站:主页 https://space.bilibili.com/208826118 参考 CGI实现文件的上传和下 ...

  2. boa(web服务器)之交叉编译、移植、cgi、文件上传篇

    boa简介 BOA 服务器是一个小巧高效的web服务器,是一个运行于unix或linux下的,支持CGI的.适合于嵌入式系统的单任务的http服务器. 源代码开放.性能高.由于它是一个单任务的Web服 ...

  3. 文件上传失败解决过程

    写了一个html+cgi实现文件上传的功能,使用html始终无法将文件上传上去,cgi解析不到文件名和文件内容.使用postman就可以上传成功.下面是源文件: post.html <!DOCT ...

  4. Java中的文件上传2(Commons FileUpload:commons-fileupload.jar)

    相比上一篇使用Servlet原始去实现的文件上传(http://www.cnblogs.com/EasonJim/p/6554669.html),使用组件去实现相对来说功能更多,省去了很多需要配置和处 ...

  5. php上传漏洞绕过gd库,jQuery File Upload任意文件上传漏洞

    事件背景 jQuery是一个快速.简洁的JavaScript框架,是继Prototype之后又一个JavaScript代码库(或JavaScript框架).jQuery File Upload一个jQ ...

  6. 00截断上传绕过_【文件上传与解析】文件上传与解析漏洞总结v1.0

    点击上方"公众号" 可以订阅哦! Hello,各位小伙伴晚上好~ 这里是依旧勤劳写公众号的小编~ 今天本公众号将推出一个新的模块,那就是漏洞知识点总结模块!!!(此处应有掌声~) ...

  7. CTFshow 文件上传 web153

    目录 思路 总结 思路 先上传带shell的png文件,上传成功 把文件后缀改成php,上传失败,改成xxxxx上传成功,得知是黑名单过滤, 上传phtml后缀,可以成功上传,但是无法解析,可以试试上 ...

  8. web安全之文件上传漏洞攻击与防范方法

    一. 文件上传漏洞与WebShell的关系 文件上传漏洞是指网络攻击者上传了一个可执行的文件到服务器并执行.这里上传的文件可以是木马,病毒,恶意脚本或者WebShell等.这种攻击方式是最为直接和有效 ...

  9. png文件头_文件上传总结

    可以参考upload-labs 检验规则 1.客户端javascript校验 通常在前端进行过滤,我们可以通过命名1.php.jpg上传,然后修改数据包文件名filename=1.php上传.或者直接 ...

最新文章

  1. 商务部数据揭示了零售行业的哪些新趋势?
  2. java 搜索业务怎么写_Java项目实战第11天:搜索功能的实现
  3. 单链表按顺序插入节点
  4. Jarvis OJ web(一)
  5. datatable绑定comboBox显示数据[C#]
  6. 2021年衢州高考的成绩查询,2021年衢州高考状元是谁分数多少分,历年衢州高考状元名单...
  7. vSphere5.1升级5.5(二)——升级Esxi主机及vmware tools
  8. VS2010 在Win 7 附加w3wp.exe进程进行调试
  9. 使用http-server搭建web服务器
  10. PHP中的数组(数据结构)
  11. JDK神坑:JAVA中Calendar的月份Month少1
  12. 冯乐乐之三,SHADERLAB入门
  13. 【java web学习小结】JSP的response对象的动态响应实例
  14. 中华文本库c语言题答案,大学计算机基础试题题库及答案(精编).doc
  15. html div 同行居中,CSS:多个DIV在同一行居中显示的一种实现方法
  16. 期货开户客户出入金是什么时间?
  17. sp经营许可证适用范围是什么?
  18. CentOS 安装声卡驱动
  19. 微小宝公众号排行榜_公众号排名 | 2020年2月公众号地区排行榜重磅发布
  20. 孤单是对你最好的惩罚

热门文章

  1. vue-router前端路由的两种模式的区别
  2. 第十七章 加密XML文档
  3. 贝塞尔曲线能够很好的拟合车道线吗?
  4. 一个网站广告位的极致使用
  5. 前端学习第三章——a标签(超链接)
  6. Arduino 各种模块篇 震动模块 常开 震动传感器模块
  7. EOS学习系统---BPS工作流程
  8. 彩色图片变成黑白打印风格图片的一种方式
  9. ArrayList 和 Vector 的区别
  10. python真的如此好吗?