使用DataURI與圖層達到網頁圖檔在資安上的議題

  • 1928
  • 0

摘要:使用DataURI與圖層達到網頁圖檔在資安上的議題

 

緣起是同事的客戶希望我們可以提供Web Service讓他們的同仁可以在內部資訊網查到本來只有承辦人可以查到的資訊。

因為我們家的報表都是Html所以還算單純,直接輸出Html String搞定收工。

只是看到報表的時後心揪了一下,怎麼有圖檔

 

於是乎請同事問客戶,圖檔到時後是不是放在他們的內部資訊網;只是得到的結果、他們內部資訊網不願意讓我們放圖檔在他們那邊,

原因為何,估計這個圖檔其實是公司章,他們可能不願意承擔這個責任吧。

好吧,那圖檔放我們這邊也是可以,無奈得到的答案:不行;因為對方IT說不希望讓同仁用太簡單的方式就知道有這個Web Service存在

另一方面,Web Service放的位置會在內部網路,不對外開放,所以圖檔放我們這邊一樣沒救 XD。

 

於是乎只好Google一下解決方案,

我用網頁內嵌圖片當關鍵字在網路上查到DataURI這個解決方案 http://waterlily-lsl.com/modules/article/view.article.php/265 (這邊有很詳細的說明,有興趣的人可以看一下)

基本上就是把圖片編譯成Base64的格式內嵌到網頁上,IE7以上、火狐、酷龍瀏覽器都有支援這樣的做法

於是乎就決定是他拉

 

(data:image/jpeg;base64, 是他的用法,後面那一大串看起來沒有意義的碼就是將圖檔編成Base64編碼以後的結果)

 

以下先介紹不寫程式的方式

(先用NotePad++把你的圖檔開起來,全選,接著用外掛模組中的MIME工具把他轉成Base64的格式)

 

(轉換成功後再把這一大串碼貼到你要內嵌的位置,大功告成 Easy)

 

接著介紹寫程式的方式

///    
/// 把檔案轉換為Base64格式的資料   
///    
/// 
   
/// 
   
///    
public string GetBase64Data(Base64Kind Kind,string FilePath)   
{   
    string contentType = string.Empty;   
    switch (Kind)   
    {   
        case Base64Kind.jpg:   
            contentType = "image/jpeg";   
            break;   
        case Base64Kind.gif:   
            contentType = "image/gif";   
            break;   
        case Base64Kind.htm:   
            contentType = "text/html";   
            break;   
        case Base64Kind.png:   
            contentType = "image/png";   
            break;   
        case Base64Kind.css:   
            contentType = "text/css";   
            break;   
    }   
    byte[] buff;   
    buff = File.ReadAllBytes(FilePath);               
    return String.Format("data:{0};base64,{1}", contentType, Convert.ToBase64String(buff));   
       
}  
view plaincopy to clipboardprint?
///    
       ///  取得HTML String,圖檔使用DataUrl方式   
       ///    
       ///    
       public string GetExpensesReportUseDataUrl()   
       {   
           StreamReader Reader = new StreamReader(System.Configuration.ConfigurationManager.AppSettings.Get("TemplatePath") + @"ExpenseDataUrl.htm");   
           string HtmlText = Reader.ReadToEnd().ToString();   
  
           //填入資料   
           HtmlText = HtmlText.Replace("col1", "900");   
           HtmlText = HtmlText.Replace("col2", "1,200");   
           HtmlText = HtmlText.Replace("col3", "500");   
           //將圖檔轉換為Base64格是並內嵌到Html String內   
           HtmlText = HtmlText.Replace("colimg",    
               new ToolKit().GetBase64Data(ToolKit.Base64Kind.jpg, System.Configuration.ConfigurationManager.AppSettings.Get("ImagePath") + @"stamp.jpg"));   
  
           Reader.Close();   
           Reader.Dispose();   
  
           return HtmlText;   
       }  
 /// <summary>
        ///  取得HTML String,圖檔使用DataUrl方式
        /// </summary>
        /// <returns></returns>
        public string GetExpensesReportUseDataUrl()
        {
            StreamReader Reader = new StreamReader(System.Configuration.ConfigurationManager.AppSettings.Get("TemplatePath") + @"ExpenseDataUrl.htm");
            string HtmlText = Reader.ReadToEnd().ToString();

            //填入資料
            HtmlText = HtmlText.Replace("col1", "900");
            HtmlText = HtmlText.Replace("col2", "1,200");
            HtmlText = HtmlText.Replace("col3", "500");
            //將圖檔轉換為Base64格是並內嵌到Html String內
            HtmlText = HtmlText.Replace("colimg", 
                new ToolKit().GetBase64Data(ToolKit.Base64Kind.jpg, System.Configuration.ConfigurationManager.AppSettings.Get("ImagePath") + @"stamp.jpg"));

            Reader.Close();
            Reader.Dispose();

            return HtmlText;
        }

(一樣蠻單純的,用上面的Method,將Return的結果置換到你要的地方)

 

其實到上面為止已經達到客戶的需求

只是有天同事問我雖然這樣做,不過使用者一樣可以按右鍵把圖檔給下載下來

的確網頁的特性就是這樣

 

解決方式,鎖右鍵?

網路上已經有一推破解方法,而且真的有心要盜用隨便用個咖圖軟體都可以把圖檔給盜下來

 

於是乎就想到如果下載圖檔的行為檔不住,那我就讓他把圖檔下下來以後也沒辦法幹嘛不就好了

(本來要回蘆洲的,一不小心想著想著就坐到輔大去了 XD)

我想到的方法是,如果我動態在公司章圖檔上加上一些特定的字眼(比如列印日期XXX表專用),

這樣一來報表本身還是有效,而使用者要是把圖檔抓走他也沒辦法幹嘛

 

而這樣的需求大概會需要三個技巧

步驟1:將文字出成圖檔

步驟2:將步驟1中輸出的圖檔壓在本來的公司章圖檔上,然後讓他成為一張新的圖

步驟3:再套用DataUrl的技術,把步驟二產生的新圖檔輸出。

 

步驟1,網路上有很多圖片驗證的機制,Google一下就有很多Sample Code,從裡面就可以找到把文字轉換成圖檔的範例

步驟2,使用GDI+的技術結合兩張圖片(GDI+ 結合兩張圖片 用這個當關鍵字找也有不少範例)

步驟3,前面兩個步驟如果都突破了,步驟三就不是難處囉

 

以下是Sample Code

 ///    
 /// 取得做好Tag的圖檔   
 ///    
 /// 
   
 /// 
要Tag上去的內容   
 ///    
 public string GetTagedImage(string SourceImagePath,string TagContent)   
 {   
  
     //原始圖檔   
     Image imgSource = Image.FromFile(SourceImagePath);   
  
     //標籤檔   
     string TagImagePath = this.CrateNewTagImg(TagContent);   
     Bitmap TagImage = new Bitmap(TagImagePath);   
     //標籤檔去背   
     TagImage.MakeTransparent();   
        
     //準備要產出的圖檔   
     Bitmap ImgOuput = new Bitmap(imgSource, imgSource.Width, imgSource.Height);   
     //準備繪圖工具   
     Graphics Grap = Graphics.FromImage(ImgOuput);   
        
     //把標籤貼上去   
     Grap.DrawImage(TagImage,new Rectangle(70,-30,ImgOuput.Width,ImgOuput.Height),   
                             0,0,ImgOuput.Width,ImgOuput.Height,GraphicsUnit.Pixel);   
  
     //定義好要產出的圖檔路徑   
     string TagedImagePath = System.Configuration.ConfigurationManager.AppSettings.Get("ImagePath") + Guid.NewGuid().ToString() + ".jpg";   
     //儲存   
     ImgOuput.Save(TagedImagePath);   
  
     Grap.Dispose();   
     TagImage.Dispose();   
     imgSource.Dispose();   
     ImgOuput.Dispose();   
  
     //把標籤檔刪掉   
     FileInfo file = new FileInfo(TagImagePath);   
     file.Delete();   
  
     //回傳已經做好Tag的圖檔路徑   
     return TagedImagePath;   
  
 }   
  
///    
/// 取得標籤圖檔   
///    
/// 
標籤內容   
///    
 private string CrateNewTagImg(string TagContent)   
 {   
     //New 一張空的圖檔   
     Bitmap Bmp = new Bitmap(300, 200);   
     //準備繪圖工具   
     Graphics Grap = Graphics.FromImage(Bmp);   
     Font font=new Font("標楷體",12);   
  
     //將圖檔翻轉30度   
     Grap.RotateTransform(30);   
     //將要簽屬的文字寫出去   
     Grap.DrawString(TagContent , font, Brushes.Blue,100,50);   
     string ImageFilePath = System.Configuration.ConfigurationManager.AppSettings.Get("TagImageWorkPath") + Guid.NewGuid().ToString()+".jpg";   
     //儲存圖檔   
     Bmp.Save(ImageFilePath);   
     Grap.Dispose();   
     Bmp.Dispose();   
  
     return ImageFilePath;   
  
 }  


///    
///  取得HTML String,圖檔使用DataUrl方式,並加Tag   
///    
///    
public string GetTagedExpensesReportUseDataUrl()   
{   
    StreamReader Reader = new StreamReader(System.Configuration.ConfigurationManager.AppSettings.Get("TemplatePath") + @"ExpenseDataUrl.htm");   
    string HtmlText = Reader.ReadToEnd().ToString();   
  
    //填入資料   
    HtmlText = HtmlText.Replace("col1", "900");   
    HtmlText = HtmlText.Replace("col2", "1,200");   
    HtmlText = HtmlText.Replace("col3", "500");   
  
    //取得已經Tag好的圖檔   
    string TagedImgFile = new ToolKit().GetTagedImage(System.Configuration.ConfigurationManager.AppSettings.Get("ImagePath") + @"stamp.jpg", "領據證明\n" + DateTime.Now.ToString("yyyy.MM.dd"));   
  
    //將圖檔轉換為Base64格是並內嵌到Html String內   
    HtmlText = HtmlText.Replace("colimg",   
        new ToolKit().GetBase64Data(ToolKit.Base64Kind.jpg, TagedImgFile));   
  
    FileInfo file = new FileInfo(TagedImgFile);   
    file.Delete();   
    Reader.Close();   
    Reader.Dispose();   
  
    return HtmlText;   
}  
        /// <summary>
        ///  取得HTML String,圖檔使用DataUrl方式,並加Tag
        /// </summary>
        /// <returns></returns>
        public string GetTagedExpensesReportUseDataUrl()
        {
            StreamReader Reader = new StreamReader(System.Configuration.ConfigurationManager.AppSettings.Get("TemplatePath") + @"ExpenseDataUrl.htm");
            string HtmlText = Reader.ReadToEnd().ToString();

            //填入資料
            HtmlText = HtmlText.Replace("col1", "900");
            HtmlText = HtmlText.Replace("col2", "1,200");
            HtmlText = HtmlText.Replace("col3", "500");

            //取得已經Tag好的圖檔
            string TagedImgFile = new ToolKit().GetTagedImage(System.Configuration.ConfigurationManager.AppSettings.Get("ImagePath") + @"stamp.jpg", "領據證明\n" + DateTime.Now.ToString("yyyy.MM.dd"));

            //將圖檔轉換為Base64格是並內嵌到Html String內
            HtmlText = HtmlText.Replace("colimg",
                new ToolKit().GetBase64Data(ToolKit.Base64Kind.jpg, TagedImgFile));

            FileInfo file = new FileInfo(TagedImgFile);
            file.Delete();
            Reader.Close();
            Reader.Dispose();

            return HtmlText;
        }

 

其實每一段程式都不難,也沒有什麼太新的技術

就是要把他全部結合在一起的時候需要多做些思考,路過有需要的人可以參考一下囉

參考資料

池水間嵌入式內聯圖片

黑暗執行蓄淺嚐Data URI

 

HtmlService.zip

HtmlServiceVB.zip