roger 发表于 2022-11-7 16:20:15

Windows VC++ 路径标准化 - PathCchCanonicalize

外部输入的参数不能直接作为文件路径,防止被恶意攻击,比如构造一个跨目录限制的文件路径…/…/…/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;
    //多字节编码转换成宽字节编码
    MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.size(), buffer, len);
    buffer = '\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;
    //宽字节编码转换成多字节编码
    WideCharToMultiByte(CP_ACP, 0, wstr.c_str(), wstr.size(), buffer, len, NULL, NULL);
    buffer = '\0';
    //删除缓冲区并返回值
    result.append(buffer);
    delete[] buffer;
    return result;
}

bool GetCanonicalizePath(const std::wstring& path, std::wstring& cannoPath)
{
    wchar_t tempArrPath = { 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 = { 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;
}

页: [1]
查看完整版本: Windows VC++ 路径标准化 - PathCchCanonicalize