Ueditor在上传图片时,服务器返回502 bad gateway的填坑记

2021-05-15 13:00

阅读:401

标签:ueditor 502 iconv

故事发生在2017.10.26下午,环宇同学跟我反应说在测试青羊双创项目的后台管理,发现在编辑园区信息时,想要上传一堆图片,用编辑器尝试上传图片时,却报了“上传失败,请重试”的错,类似下图:

技术分享

纳尼?我...... 多么正常的编辑器,我本地跑的好好的,我赶紧去试了一下,果然报错,WTF......

但是:虽然报错,当点击“在线管理”(就是选择服务器上已存在的文件)的时候,却发现之前那张图是传上去了的,有些个尴尬,马上和环宇说其实已传上去了,可以直接在“在线管理”里先用着...为了要给客户弄好内容,他没有多言,应声了下来,但很明显,环宇虽然口头不说,但心里肯定在骂“我*”,我想bug还是得改,于是:

解bug第一式:用Chrome浏览器,按下F12,打开Network,去上传一波,然后我就看到这样的画面:

技术分享

技术分享

大家都是明白人,其他就不多说了,找到了对应的后端代码,也看到了返回值,那赶紧找到此这个文件看看代码再说。

好吧,路径是个绝对路径,就是Ueditor的上传文件的后台代码实现(不过是PHP版而已),目录结构是这样的:

技术分享

此处略去N个字,contoller.php调用了action_upload.php,再调用了Uploader.class.php。

解bug第二式:打断点,打了尼玛好多,终于找到出问题的代码是在这里:

技术分享

也就是说是iconv这个函数引起了报错,一看上下文,这也没什么特别的用处,就是把一句提示信息转一下码而已,只要注释掉这句就可以了,程序照常运行,也不会报错,先回复环宇说bug已解,可以正常使用。

/**
* Created by JetBrains PhpStorm.
* User: taoqili
* Date: 12-7-18
* Time: 上午11: 32
* UEditor编辑器通用上传类
*/
class Uploader
{
private $fileField; //文件域名
private $file; //文件上传对象
private $base64; //文件上传对象
private $config; //配置信息
private $oriName; //原始文件名
private $fileName; //新文件名
private $fullName; //完整文件名,即从当前配置目录开始的URL
private $filePath; //完整文件名,即从当前配置目录开始的URL
private $fileSize; //文件大小
private $fileType; //文件类型
private $stateInfo; //上传状态信息,
private $stateMap = array( //上传状态映射表,国际化用户需考虑此处数据的国际化
"SUCCESS", //上传成功标记,在UEditor中内不可改变,否则flash判断会出错
"文件大小超出 upload_max_filesize 限制",
"文件大小超出 MAX_FILE_SIZE 限制",
"文件未被完整上传",
"没有文件被上传",
"上传文件为空",
"ERROR_TMP_FILE" => "临时文件错误",
"ERROR_TMP_FILE_NOT_FOUND" => "找不到临时文件",
"ERROR_SIZE_EXCEED" => "文件大小超出网站限制",
"ERROR_TYPE_NOT_ALLOWED" => "文件类型不允许",
"ERROR_CREATE_DIR" => "目录创建失败",
"ERROR_DIR_NOT_WRITEABLE" => "目录没有写权限",
"ERROR_FILE_MOVE" => "文件保存时出错",
"ERROR_FILE_NOT_FOUND" => "找不到上传文件",
"ERROR_WRITE_CONTENT" => "写入文件内容错误",
"ERROR_UNKNOWN" => "未知错误",
"ERROR_DEAD_LINK" => "链接不可用",
"ERROR_HTTP_LINK" => "链接不是http链接",
"ERROR_HTTP_CONTENTTYPE" => "链接contentType不正确",
"INVALID_URL" => "非法 URL",
"INVALID_IP" => "非法 IP"
);

/**
* 构造函数
* @param string $fileField 表单名称
* @param array $config 配置项
* @param bool $base64 是否解析base64编码,可省略。若开启,则$fileField代表的是base64编码的字符串表单名
*/
public function __construct($fileField, $config, $type = "upload")
{
    $this->fileField = $fileField;
    $this->config = $config;
    $this->type = $type;
    if ($type == "remote") {
        $this->saveRemote();
    } else if($type == "base64") {
        $this->upBase64();
    } else {
        $this->upFile();
    }

    $this->stateMap[‘ERROR_TYPE_NOT_ALLOWED‘] = iconv(‘unicode‘, ‘utf-8‘, $this->stateMap[‘ERROR_TYPE_NOT_ALLOWED‘]);
}


回头来看这句 $this->stateMap[‘ERROR_TYPE_NOT_ALLOWED‘] = iconv(‘unicode‘, ‘utf-8‘, $this->stateMap[‘ERROR_TYPE_NOT_ALLOWED‘]); 是个什么鬼,我的疑问有三点:

1.为毛这里要转这一句提示信息,而不转其他的?

2.iconv是什么函数?

3.就算要转,为毛写死了unicode到utf-8,为毛不是gb2312或gbk?

是的,我来解答这几个问题,首先第一个....不 我先说第二个:

iconv是一个从PHP4以后有的函数,功能是把字符串从一种编码转换成另一种编码,详情在这里可以查看:http://php.net/manual/en/function.iconv.php

那编码又是什么意思呢,大概就是计算机存储信息时最终是二进制,然全世界有很多国家和语言,慢慢变成同样的二进制数字表示的字符不一样,通常听到的UTF-8,GB2312等,就是不同的编码方式的意思,而ANSI,Unicode等就是不同的字符集的意思,详情可以查看:http://blog.jobbole.com/84903/ ,或者 http://blog.csdn.net/wabil/article/details/50807240 。这里不多讲。

那为什么要写死了了unicode到utf-8呢?那我就不知道了,一脸懵逼的时候,看到头部:

/**
* Created by JetBrains PhpStorm.
* User: taoqili
* Date: 12-7-18
* Time: 上午11: 32
* UEditor编辑器通用上传类
*/

好吧,解bug第三式:百度一下taoqili,第一条便是https://my.oschina.net/taoqili/ ,嗯,看起来是其作者本人的主页,因为这个主页进去第一篇文章依然是5年前说Ueditor上线的文章 ....

技术分享

于是进去此文章 https://www.oschina.net/news/37279/ueditor-1-2-5 ,无非就是说新版本上线了,文章 最后附了Ueditor的链接:

技术分享

是链接到 http://ueditor.baidu.com/website/download.html#ueditor ,好吧,官网的页面....,然后引人注目的是这句话:

技术分享

再次懵逼的我,又打开了这个链接 https://github.com/fex-team/ueditor/blob/dev-1.5.0/php/Uploader.class.php ,不错,这个文件内容是替换了的(不死心的我还下载了此页面下方一些其他版本,看到Uploader.class.php的内容是和本地一样) ,然回到此页面的上一级 https://github.com/fex-team/ueditor/tree/dev-1.5.0/php ,如图:

技术分享

就是说其他文件在4年前就搬到git,这个文件是最近修改过了(PS:https://github.com/fex-team 是百度前端的git主页),下载此文件,做了对比,也没啥特别的,重要的是:

技术分享

直接把上面有bug的给换了个函数,我汗,那这个mb_convert_encoding又是做嘛的?http://www.php.net/manual/en/function.mb-convert-encoding.php ,和iconv类似,也是转编码用的,但为啥换成这个了? 其大概意思是iconv在中文(或者说非英文)时会有一些乱码问题,比如有增加后缀 //TRANSLIT 和 //IGNORE 的用法,并且需要指定从啥转换成啥的两个”啥“,而mb_convert_encoding可以不用指定从啥到啥,因为有个万能的”auto“参数,具体的大家自己百度有一堆文章在讲这两个函数,这里不多讲,最重要的结论就是:mb_convert_encoding兼容好一些,但效率差一些...

好吧,我就认了,跳过...但是上上图中

技术分享

提到的是修复了ssrf的安全漏洞....可刚才替换iconv的函数和ssrf好像没半毛钱关系(这就是所谓的掩人耳目吗),好吧,继续对比两份文件,在后面一个saveRemote 方法里(这个方法是编辑器允许引用一张在网络上已存在的真实的图片地址,一般是指绝对路径的URL),新版的代码多了几行:

 

//检查文件内容是否真的是图片
if (substr(mime_content_type($this->filePath), 0, 5) != ‘image‘) {
    $this->stateInfo = $this->getStateInfo("ERROR_TYPE_NOT_ALLOWED");
    return;
}

bingo 就是他了,那么问题来了,什么是ssrf?好吧

SSRF(Server-Side Request Forgery ,服务器端请求伪造)是一种由攻击者构造形成由服务器发起请求的一个安全漏洞,SSRF的主要攻击目标为外网无法访问的内部系统
原因?
SSRF形成的原因是服务端提供了从其他服务器应用获取数据的功能,在用户可控的情况下,未对目标地址进行过滤与限制,导致此漏洞的产生。
比如从指定URL地址获取网页文本内容,加载指定地址的图片等,都是SSRF容易出现的点。详情依然请大家自行百度。

简单来讲就是服务器上会访问其信任的第三方URL,如下面一个实例:

http://www.douban.com/***/service?image=http://www.baidu.com/img/bd_logo1.png

所以理论上要信任这个URL,是需要做一些限制和判断的,很多网页的分享功能,就有类似的原理,而上面的:检查文件内容是否真的图片,就是对其文件格式做了判断,避免非图片的URL被访问到了。

回头再倒个序:当我发现是那iconv引起的bug时,我突然想起前几日严旭同学和航航写公告功能的时候,加了Ueditor的,所以跑去库里追他的代码,发现他其实自己给前端写了一个上传文件的接口,走我们mhi常用的common/upload去了,然再跟发现,他最终实现上传的代码,依然是拷的Ueditor的Uploader.class.php来实现的,并且,他把那句iconv函数的注释了,然后我就问他为啥要注释呢,他说因为那句不注释就要报错~~,我俩就尴尬的对视着,5秒之后我说好吧我知道了,然再5秒之后他问我:那你知道为啥要报错吗,sorry,又是尴尬的对视,我说:我也不知道,画面大家自行脑补。。。


好吧,说了那么多,绕的挻远的,回头总结一下我本身想记的坑,也是本文的小结:

1.多语言造成的字符集和字符编码的问题,比如常用的Unicode和ANSI字符集,UTF-8和GBK编码,导致在windows和Linux、中文和英文操作系统里、中文编码的代码文件和英文编码的数据库间,需要用字符编码转换函数进行转换来解决乱码的问题,特别是开发环境是windows,生产环境是Linux时要注意;

2.iconv和mb_convert_encoding都是php中转换编码的函数,大概区别在于:1.iconv效率高,但容易出错,2.mb_convert_encoding兼容性好,但效率偏低,3两个函数是依赖于不同的php扩展;

3.ssrf漏洞是指:当服务器允许访问第三方URL,并且这个第三方URL是由用户决定,那如果对这个URL未做严格的控制,可能会有漏洞;

4.Ueditor官网上的代码,是5年前的了,要继续用这个编辑器的童鞋,请到百度前端git页去下载 https://github.com/fex-team/ueditor


Well,如果你很偏执,你可能会问我上面提的三个问题中第一个问题我好像没回答,那我现在回答你:我没找到答案......

所以,晚了,躺下就睡吧。


Ueditor在上传图片时,服务器返回502 bad gateway的填坑记

标签:ueditor 502 iconv

原文地址:http://357989.blog.51cto.com/347989/1977271


评论


亲,登录后才可以留言!