顯示具有 C# 標籤的文章。 顯示所有文章
顯示具有 C# 標籤的文章。 顯示所有文章

2018年12月25日 星期二

[MongoDB] C# Driver 時間查詢問題


今天查詢 MongoDB 帶時間條件遇到一個怪問題,
時間條件設定為 2018-12-24T16:00:00Z
但進資料庫查詢時,總是被改成 ISODate("2018-12-24T08:00:00Z")

經一番查詢後,發現 MongoDB driver 在查詢時,
會自動依執行環境的 Time Zone 改成 UTC 時間,
所以才會發生這個怪現象
2018-12-24T16:00:00Z  → time zone (utc+8) → 2018-12-24T08:00:00Z


那該如何解決呢?
var queryDate = new DateTime(2018, 12, 24, 0, 0, 0, DateTimeKind.Utc);
在建立DateTime 時,帶入 DateTimeKind.Utc  ,
即告訴 driver 時間已經是 UTC 時間,
所以不用再幫我轉囉!!
reference: https://stackoverflow.com/questions/19350348/mongodb-c-sharp-driver-and-isodate

2017年11月1日 星期三

Error: The 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine.

使用 LinqToExcel 突然發生 error,原來是安裝 windows update 後,發生的慘案
Error: The 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine.

解決方案如下:

1. uninstall KB4041676 on Windows 10 and KB4041681 on Windows 7.

2. Find prior version (4.0.9801.0) of msexcl40.dll

3. Place in another directory. They suggest the application directory, but since in the next step you will modify registry to point to this older version, it can probably go anywhere.

4. Update registry key HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Jet\4.0\Engines\Excel\win32 to point to the location from step 2.

但此招是救急,可能有安全性的疑慮!

2016年9月6日 星期二

Prevent Cross-Site Request Forgery (CSRF) using ASP.NET MVC’s AntiForgeryToken()

什麼是 Cross-Site Request Forgery (CSRF)

簡單來說,CSRF 就是使用者在不知情的情況,讓瀏覽器送出請求給目標網站以達攻擊目的。

使用者進行網路驗證後,瀏覽器會將驗證資訊存在 Cookie , 若使用者未登出,此 Cookie 仍視為有效, 而使用者瀏覽其他網站時,會將此驗證資訊回傳 server 以便進行操作, 此時使用者在不自覺的情況下,瀏覽含有攻擊程式碼的網頁, 駭客可使用相同一份驗證資訊(使用者身份)進行攻擊。

如何預防 CSRF

在 View 上 加入 @Html.AntiForgeryToken()
<!-- Contained in xxxxx.cshtml -->
@model MileageStats.ServicesModel.User
@Html.AntiForgeryToken()

在 client 端,即可檢視會產出 hidden input html
<!-- Rendered HTML in the client browser -->
<input name="__RequestVerificationToken" 
  type="hidden" 
  value="H4zpQFvPdmEdGCLsFgeByj0xg+BODBjIMvtSl5anoNaOfX4V69Pt1OvnjIbZuYrpgzWxWHIjbn
  zFOLxP5SzVR4cM9XZeV78IPi8K4ewkM3k2oFkplrXL4uoAqy+aoSOg8s1m1qxrE7oeBBtvezEHCAs6nKE
  h2jAwn3w0MwmhkcDQiJfJK7hGvN0jXA4d7S8x7rbLxp4Y8IJZS9wka2eOLg==" />

在 controller action 加上 ValidateAntiForgeryTokenAttribute
// Contained in xxxxController.cs
[HttpPost]
[ValidateInput(false)]
[ValidateAntiForgeryToken]
public ActionResult Edit(....)

透過 AntiForgeryToken 來檢查連線是否是正常的,
簡單的兩個步驟就完成囉!

參考:https://msdn.microsoft.com/en-us/library/hh404095.aspx

2016年9月5日 星期一

Preventing Open Redirection Attacks

前一陣子維護的 web 進行安全性掃描,
被列了一個 issue ,就是 open redirection attack,
至於什麼是  open redirection attack ,又該如何解決呢?
有興趣就接著往下看吧!


What's Open Redirection Attacks ?

Any web application that redirects to a URL that is specified via the request such as the querystring or form data can potentially be tampered with to redirect users to an external, malicious URL. This tampering is called an open redirection attack.


舉例來說,當某頁面需要登入權限,但還未登入時,當輸入網址後,會被導至登入頁,
在登入成功後,透過 returnUrl 會再導回原頁面,
如:
當我想進入 http://somewebhost/xxx/list
因為還未登入,所以被導至 http://somewebhost/Account/LogOn?returnUrl=/xxx/list
但成功登入後,則透過 returnUrl 導至 http://somewebhost/xxx/list

這一切都很完美,但對有心人士來說,也很完美,
怎麼說呢? 就是透過 returnUrl 這個特性,可以把使用者導引至惡意網站,

可以這麼做,組成以下連結,讓使用者誤以為進入正確的網站(也許是某金融網站 )
http://somewebhost/Account/LogOn?returnUrl=http://someBadWeb/doSomething

但成功登入後,卻會將使用者導至另一個惡意網站,而使用者會以為是正常的登入成功,
可能因此填入重要個資,如信用卡號碼等等,
形成一種釣魚網站的手法,十分可怕

該如何預防?

就是檢查 returnUrl 是否是合法的,也就是說只能導至目前 host 下的網址,

在 asp.net MVC3 以上的寫法,
使用 System.Web.Mvc.Url helper 類別方法 IsLocalUrl() ,
來判斷 returnUrl 是否是合法的,如下:
public ActionResult LogOn(LogOnModel model, string returnUrl)
{    
 if (Url.IsLocalUrl(returnUrl))
 {
  return Redirect(returnUrl);
 }
 else
 {
  return RedirectToAction("Index", "Home");
 }
}

若不是 MVC 專案,
則可利用以下方法進行驗證:
public static bool IsUrlLocalToHost(this HttpRequestBase request, string url)
{
   return !url.IsEmpty() &&
          ((url[0] == '/' && (url.Length == 1 ||
           (url[1] != '/' && url[1] != '\\'))) || 
           (url.Length > 1 &&
            url[0] == '~' && url[1] == '/'));
}

以上就可以解決此 issue 囉!

參考:http://www.asp.net/mvc/overview/security/preventing-open-redirection-attacks

2016年8月24日 星期三

json.net 反序列化繼承的子類別問題

今天遇到 json.net 反序列化的問題,
( json.net deserilize dirven class problem! )

前情提要:

開發 web, server 與 client 透過 json 格式傳遞資料,
server 端在定義 ViewMode 時,DataModel 可能是 ChildAModel 或 ChildBModel 類別,
以 OO多型 ( Polymorphism ) 的設計來說,
實作一個父類 ( BaseModel ) 讓 ChildAModel, ChildBModel 繼承,
這樣 ViewModel.DataModel 就可以指定 ChildAModel, ChildBModel 其中之一的資料格式
如下:
public class BaseModel
{
 public int key { get; set; }
}

public class ChildAModel: BaseModel
{
 public string Name { get; set; }
 public int Age { get; set; }
}

public class ChildBModel : BaseModel
{
 public string SomeProperty1 { get; set; }
 public int SomeProperty2 { get; set; }
}

public class ViewModel
{
 public BaseModel DataModel { get; set; }
}

問題:

依這樣的設計,
將 ViewModel 的資料轉成 JSON 拋給 Client 沒問題,
JavaScript 本身就是延展性高的語言,

但由 Client 再拋給 Server 時,
Json.Net 將 JSON 反序列成物件時,
問題來了!
ViewModel.DataModel 只會被反序列化成 BaseModel ,
其他資料全掉光了,
傷腦筋啦! 該如何是好呢?

Solution:

基本概念是靠實作 CustomCreationConverter.Create 來通知 Json.Net 反序列化 T 時,
要轉成哪一種類別,但此 Create 原生方法卻沒有提供其他資訊來判斷該用哪種類別
example:
public interface IPerson
{
    string FirstName { get; set; }
    string LastName { get; set; }
    DateTime BirthDate { get; set; }
}

public class Employee : IPerson
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime BirthDate { get; set; }

    public string Department { get; set; }
    public string JobTitle { get; set; }
}

public class PersonConverter : CustomCreationConverter
{
    public override IPerson Create(Type objectType)
    {
        return new Employee();
    }
}

發現有善心人士也遇到此問題,並公開解法
覆寫 JsonConverter,擴充 Create 方法
如下: ( 參考 )
public abstract class JsonCreationConverter : JsonConverter
{
 protected abstract T Create(Type objectType, JObject jsonObject);

 public override bool CanConvert(Type objectType)
 {
  return typeof(T).IsAssignableFrom(objectType);
 }

 public override object ReadJson(JsonReader reader, Type objectType, 
  object existingValue, JsonSerializer serializer)
 {
  var jsonObject = JObject.Load(reader);
  var target = Create(objectType, jsonObject);
  serializer.Populate(jsonObject.CreateReader(), target);
  return target;
 }

 public override void WriteJson(JsonWriter writer, object value, 
  JsonSerializer serializer)
 {
  throw new NotImplementedException();
 }
}

再自訂 Json.Net Conveter,並依物件的 property 回覆類別,如下

public class ModelConverter : JsonCreationConverter
{
 protected override BaseModel Create(Type objectType, 
  JObject jsonObject)
 {
  if (jsonObject["Name"] != null)
  {
   return new ChildAModel();
  }
  else if (jsonObject["SomeProperty1"] != null)
  {
   return new ChildBModel();
  }
  else
  {
   return new BaseModel();
  }
 }
}

最後反序列化的使用方式,如下:

var deserializedModel = JsonConvert.DeserializeObject<BaseModel>(json,
  new ModelConverter ());

以上!

2016年6月8日 星期三

unable to read data from the transport connection an existing connection was forcibly closed by remote host

今天遇到一案例,
使用 WebClient 下載檔案,
卻拋出以下錯誤訊息:
unable to read data from the transport connection an existing connection was forcibly closed by remote host

解決方式:
在建立 WebClient 前,加入此行,即可
System.Net.ServicePointManager.Expect100Continue = false;

那什麼要將 Expect100Continue 設為 false 呢?
因為 Server 跟 Client 在溝通時,中途會經過很多節點,如 proxy,
但這些節點不一定支援 Expect100Continue 進而拋出此 exception

那 Expect100Continue  又是什麼?
簡單來說是為了減少網路流量所設計的機制,原因如下:( 參考 msdn )

For example, assume the Expect100Continue property is false.When the request is sent to the server, it includes the data.If, after reading the request headers, the server requires authentication and must send a 401 response, the client must resend the data with proper authentication headers.

If this property is true, the request headers are sent to the server.If the server has not rejected the request, it sends a 100-Continue response signaling that the data can be transmitted.If, as in the preceding example, the server requires authentication, it sends the 401 response and the client has not unnecessarily transmitted the data.