Windows VC++路径标准化-PathCchCanonicalize

2022-09-21 10:36:33 浏览数 (2)

外部输入的参数不能直接作为文件路径,防止被恶意攻击,比如构造一个跨目录限制的文件路径…/…/…/etc/passwd或…/…/boot.ini,或构造一个指向系统关键文件的链接文件symlink(“/etc/shadow”,“tmp/log”)。PS "./“表示当前目录,可以不写,”…/"表示当前目录的上一级目录,即当前目录的父目录。windows可以用PathCanonicalizeA或者PathCanonicalizeW检查文件目录是否标准,但是微软msdn官网不建议使用PathCanonicalize这个函数,如下图所示:

微软msdn官网说误用PathCanonicalizeA 会导致buffer溢出,建议使用更安全的PathCchCanonicalize或PathCchCanonicalizeEx 代替。

对PathCchCanonicalize函数的使用示例如下:

代码语言:javascript复制
#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] = '';             //添加字符串结尾  
    //删除缓冲区并返回值  
    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] = '';
    //删除缓冲区并返回值  
    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_1name_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_1name_2
    } else {
        std::cout << "GetCanonicalizePathA failed, lastErrorCode: " << GetLastError() << endl;
    };

    return 0;
}

运行结果如下图所示:

0 人点赞