[ASP.NET]Path Manipulation(Input Validation and Representation, Data flow)

當程式被原始碼安全檢測工具掃出「Path Manipulation」的 issue ,要怎麼辦呢?

有時程式中操作檔案會依QueryString或是某個TextBox的值來決定要Copy還是要Delete。

但這樣的做法會被原始碼安全檢測工具掃出「Path Manipulation(Input Validation and Representation, Data flow)」的 issue !

以下用範例來說明,

WebForm1.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" 
Inherits="WebApplication1.WebForm1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:TextBox ID="txtFileName" runat="server" Text="README.TXT"></asp:TextBox>
        <!-- File Delete -->
        <asp:Button ID="Button1" runat="server" Text="DeleteFile_1" OnClick="Button1_Click" />
        <asp:Button ID="Button2" runat="server" Text="DeleteFile_2" OnClick="Button2_Click" />
        <!-- File Copy -->
        <asp:Button ID="Button3" runat="server" Text="CopyFile_1" OnClick="Button3_Click" />
        <asp:Button ID="Button4" runat="server" Text="CopyFile_2" OnClick="Button4_Click" />
    </div>
    </form>
</body>
</html>

 

WebForm1.aspx.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;

namespace WebApplication1
{
    public partial class WebForm1 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
        }

        protected void Button1_Click(object sender, EventArgs e)
        {
            //假如我們的Web AP下有Data目錄 
            string dataFolderPath = Server.MapPath(@"~\Data\");
            string fileName = txtFileName.Text;
            string deleteFilePath = Path.Combine(dataFolderPath, fileName);
            if (File.Exists(deleteFilePath))
                File.Delete(deleteFilePath);
        }

        protected void Button2_Click(object sender, EventArgs e)
        {
            //假如我們的Web AP下有Data目錄 
            string dataFolderPath = Server.MapPath(@"~\Data\");
            string fileName = txtFileName.Text;
            DeleteFile(dataFolderPath, fileName);
        }

    
        void DeleteFile(string folderName, string delFileName)
        {
            foreach (string fullFileName in Directory.EnumerateFiles(folderName))
            {
                string fileName = Path.GetFileName(fullFileName);
                if (delFileName.ToUpper() == fileName.ToUpper())
                {
                    File.Delete(fullFileName);
                }
            }
        }

        protected void Button3_Click(object sender, EventArgs e)
        {
            //假如我們的Web AP下有Data目錄 
            string dataFolderPath = Server.MapPath(@"~\Data\");
            //假如我們的Web AP下有Temp的目錄
            string tempFolderPath = Server.MapPath(@"~\temp\");
            string fileName = txtFileName.Text;
            string tempFile = Path.Combine(tempFolderPath, fileName);
            string dataFile = Path.Combine(dataFolderPath, fileName);
            if(File.Exists(tempFile))
                File.Copy(tempFile, dataFile, false);
        }

        protected void Button4_Click(object sender, EventArgs e)
        {
            //假如我們的Web AP下有Data目錄 
            string dataFolderPath = Server.MapPath(@"~\Data\");
            //假如我們的Web AP下有Temp的目錄
            string tempFolderPath = Server.MapPath(@"~\temp\");
            string fileName = txtFileName.Text;
            CopyFile(tempFolderPath, dataFolderPath, fileName);
        }

        void CopyFile(string sourcePath, string destPath, string fileName)
        {
            //假如我們的Web AP下有Data目錄 
            foreach (string fullFileName in Directory.EnumerateFiles(sourcePath))
            {
                string sourceFileName = Path.GetFileName(fullFileName);
                if (fileName.ToUpper() == sourceFileName.ToUpper())
                {
                    string destFilePath = Path.Combine(destPath, sourceFileName);
                    File.Copy(fullFileName, destFilePath, true);
                }
            }
        }
    }
}

image

 

先來看看 Delete 檔案的部份,如 Button1_Click Method,

//假如我們的Web AP下有Data目錄 
string dataFolderPath = Server.MapPath(@"~\Data\");
string fileName = txtFileName.Text;
string deleteFilePath = Path.Combine(dataFolderPath, fileName);
if (File.Exists(deleteFilePath))
	File.Delete(deleteFilePath);

 

刪除的檔案是從畫面上的TextBox(txtFileName.Text)而來的,所以它是 不可靠,有風險 的!

所以這時,原始碼安全檢測工具就會賞你「Path Manipulation Critical issue」。

那要如何修正呢?

把握一個原則,針對檔案操作,不能使用 有風險的檔名 ,這樣就可以了!

所以新增一個刪除檔案的 Method ,然後拿 有風險的檔名 跟某個目錄裡的檔案去比較,有找到的話,再針對找到的檔名操作就可以了,如下,

void DeleteFile(string folderName, string delFileName)
{
	foreach (string fullFileName in Directory.EnumerateFiles(folderName))
	{
		string fileName = Path.GetFileName(fullFileName);
		if (delFileName.ToUpper() == fileName.ToUpper())
		{
			File.Delete(fullFileName);
			break;
		}
	}
}

請注意,我們是針對 fullFileName 操作哦!

 

所以使用的話,就改成如 Button2_Click Method 的內容,如下,

//假如我們的Web AP下有Data目錄 
string dataFolderPath = Server.MapPath(@"~\Data\");
string fileName = txtFileName.Text;
DeleteFile(dataFolderPath, fileName);

 

Copy 檔案,如 Button3_Click Method 內容,在 File.Copy 及 File.Exists 都會有「Path Manipulation issue」,如下,

//假如我們的Web AP下有Data目錄 
string dataFolderPath = Server.MapPath(@"~\Data\");
//假如我們的Web AP下有Temp的目錄
string tempFolderPath = Server.MapPath(@"~\temp\");
string fileName = txtFileName.Text;
string tempFile = Path.Combine(tempFolderPath, fileName);
string dataFile = Path.Combine(dataFolderPath, fileName);
if(File.Exists(tempFile))
	File.Copy(tempFile, dataFile, false);

 

所以,這時操作也是要讓它操作 沒風險的檔案名稱 ,所以新增一個 CopyFile Method,來比較,並負責Copy File,如下,

void CopyFile(string sourcePath, string destPath, string fileName)
{
	//假如我們的Web AP下有Data目錄 
	foreach (string fullFileName in Directory.EnumerateFiles(sourcePath))
	{
		string sourceFileName = Path.GetFileName(fullFileName);
		if (fileName.ToUpper() == sourceFileName.ToUpper())
		{
			string destFilePath = Path.Combine(destPath, sourceFileName);
			File.Copy(fullFileName, destFilePath, true);
			break;
		}
	}
}

 

所以使用的話,就改成如 Button4_Click Method 的內容,如下,

//假如我們的Web AP下有Data目錄 
string dataFolderPath = Server.MapPath(@"~\Data\");
//假如我們的Web AP下有Temp的目錄
string tempFolderPath = Server.MapPath(@"~\temp\");
string fileName = txtFileName.Text;
CopyFile(tempFolderPath, dataFolderPath, fileName);

 

以上是筆者的解法,如果有其他的方式,也請讓我知道哦!

2014/03/27 補充使用LINQ去Search File,如下,

void DeleteFileLINQ(string folderName, string delFileName)
{
	var searchFile = (from f in Directory.EnumerateFiles(folderName)
				   where Path.GetFileName(f).ToUpper() == delFileName.ToUpper()
				   select f).FirstOrDefault();
	if (!string.IsNullOrEmpty(searchFile))
		File.Delete(searchFile);
}

void CopyFileLINQ(string sourcePath, string destPath, string fileName)
{
	//假如我們的Web AP下有Data目錄 
	var sourceFile = (from f in Directory.EnumerateFiles(sourcePath)
					  where Path.GetFileName(f).ToUpper() == fileName.ToUpper()
					  select f).FirstOrDefault();
	if (!string.IsNullOrEmpty(sourceFile))
	{
		string sourceFileName = Path.GetFileName(sourceFile);
		string destFilePath = Path.Combine(destPath, sourceFileName);
		File.Copy(sourceFile, destFilePath, true);
	}
}

 

參考資料

Input Validation and Representation Server.HtmlEncode Replace Tool

Fortify白箱測試Critical issue: Path Manipulation

Hi, 

亂馬客Blog已移到了 「亂馬客​ : Re:從零開始的軟體開發生活

請大家繼續支持 ^_^