外部输入的参数不能直接作为文件路径,防止被恶意攻击,比如构造一个跨目录限制的文件路径…/…/…/etc/passwd 或…/…/boot.ini,或构造一个指向系统关键文件的链接文件 symlink (“/etc/shadow”,“tmp/log”)。PS "./“表示当前目录,可以不写,”…/" 表示当前目录的上一级目录,即当前目录的父目录。windows 可以用 PathCanonicalizeA 或者 PathCanonicalizeW 检查文件目录是否标准,但是微软 msdn 官网不建议使用 PathCanonicalize 这个函数,如下图所示:
微软 msdn 官网说误用 PathCanonicalizeA 会导致 buffer 溢出,建议使用更安全的 PathCchCanonicalize 或 PathCchCanonicalizeEx 代替。
对 PathCchCanonicalize 函数的使用示例如下:
#include <Windows.h>
#include <pathcch.h>
#include <string>
#include <iostream>
#pragma comment(lib,"Pathcch.lib")
using namespace std;
//将string转换成wstring
wstring String2WString(string str)
{
wstring result;
//获取缓冲区大小,并申请空间,缓冲区大小按字符计算
int len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), NULL, 0);
TCHAR* buffer = new TCHAR[len + 1];
//多字节编码转换成宽字节编码
MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), buffer, len);
buffer[len] = '\0'; //添加字符串结尾
//删除缓冲区并返回值
result.append(buffer);
delete[] buffer;
return result;
}
//将wstring转换成string
string WString2String(wstring wstr)
{
string result;
//获取缓冲区大小,并申请空间,缓冲区大小事按字节计算的
int len = WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), NULL, 0, NULL, NULL);
char* buffer = new char[len + 1];
//宽字节编码转换成多字节编码
WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), buffer, len, NULL, NULL);
buffer[len] = '\0';
//删除缓冲区并返回值
result.append(buffer);
delete[] buffer;
return result;
}
bool GetCanonicalizePath(const std::wstring& path, std::wstring& cannoPath)
{
wchar_t tempArrPath[MAX_PATH] = { 0 };
if (path.empty() || path.length() > MAX_PATH ||
PathCchCanonicalize(tempArrPath, MAX_PATH, path.c_str()) != S_OK) {
return false;
}
std::wstring resultPath = tempArrPath;
cannoPath = resultPath;
return true;
}
bool GetCanonicalizePathA(const std::string& path, std::string& cannoPath)
{
std::wstring wstrPath = String2WString(path);
wchar_t tempArrPath[MAX_PATH] = { 0 };
if (wstrPath.empty() || wstrPath.length() > MAX_PATH ||
PathCchCanonicalize(tempArrPath, MAX_PATH, wstrPath.c_str()) != S_OK) {
return false;
}
std::wstring resultPath = tempArrPath;
std::string strTempResultPath = WString2String(resultPath);
cannoPath = strTempResultPath;
return true;
}
int main(int argc, char* argv[])
{
std::string fileFullPath = "D:\\name_1\\.\\name_2\\.\\name_3\\..\\name_4\\..";
std::string canonicalizePath;
bool bCanonicalizeOk = GetCanonicalizePathA(fileFullPath, canonicalizePath);
if (bCanonicalizeOk) {
std::cout << "canonicalizePath=" << canonicalizePath.c_str() << endl; // D:\name_1\name_2
} else {
std::cout << "GetCanonicalizePathA failed, lastErrorCode: " << GetLastError() << endl;
};
std::wstring fileFullWstrPath = L"D:\\name_1\\.\\name_2\\.\\name_3\\..\\name_4\\..";
std::wstring canonicalizeWstrPath;
bCanonicalizeOk = GetCanonicalizePath(fileFullWstrPath, canonicalizeWstrPath);
if (bCanonicalizeOk) {
std::cout << "canonicalizeWstrPath=" << WString2String(canonicalizeWstrPath).c_str() << endl; // D:\name_1\name_2
} else {
std::cout << "GetCanonicalizePathA failed, lastErrorCode: " << GetLastError() << endl;
};
return 0;
}
|