IT業界のすみっこ暮らし

ふと気がついたときの記録

ASP.NET MVC:レスポンスヘッダにCookieを設定

セキュリティ設定なし

Response.AppendHeader("Set-Cookie", "testCookie=1234; path=/");

セキュリティ設定あり

Response.AppendHeader("Set-Cookie", "testCookie=1234; path=/; Secure; HttpOnly");

参考サイト

developer.mozilla.org

ASP.NET MVC:logout時のcookieセキュア対応について

ログイン時のCookieのセキュア設定

f:id:papamau:20171107185739p:plain

うん、問題ない。

ログアウト時のCookieのセキュア設定

f:id:papamau:20171107185711p:plain

ログアウトされたので、Cookieの値は空。

でも、値がないとは言え、HttpOnly設定もSecureも設定されていない。

設定は以下の記事通り設定済み。

pie001.hatenablog.com

ふと不安になって調べてみた

stackoverflow.com

要はlogoutでCookieを削除するときは値に空が設定されるのでもう敏感なデータはCookieから削除されている。よって悪い人が何かやろうとしても出来ないんで特に設定する必須はない。

結論

このままで問題ない。

恐らくCookieに値があるときのみ、設定が有効になるのではないかと思われるが、これの調査はまた後日で。

C#:コレクション型の比較

※2015/07チーム内で共有するためにまとめた内容。

IEnumerable

  • 全ての始まり(以下全てのインタフェースの親に当てはまる)。
  • foreachはIEnumerableインターフェースを実装しているクラスしか処理することができません。
  • 特定のアイテムを取得することは出来ない。(ex)0~4までのアイテムがある場合、0~3を通さず4を取得できない)
  • 読み取り専用。追加と削除が出来ない。
  • DBサーバーから取得した値からクエリーを処理する。DBContextで直接利用する場合、メモリーの問題が発生する恐れがある。

IQueryable

  • クエリーは.ToList()もしくはforeachで反復処理を行うまで実行されない。
  • DBサーバーで実行されるクエリーを生成して値を処理する。
  • Ienumerableを継承している。

IEnumerableとIQueryableの比較

  • IQueryableはIEnumerableを継承している。
  • IEnumerableはDBサーバーから取得した値からクエリーを処理する。DBContextで直接利用する場合、メモリーの問題が発生する恐れがある。
  • IQueryableはDBサーバーで実行されるクエリーを生成して値を処理する。

ICollection

  • IEnumerableとIListの間に位置している。
  • IEnumerableを継承している。
  • 追加、削除処理と数の取得が可能。(Add(), Remove(), Count)

IList

  • アイテムの追加、削除、修正が可能。
  • 特定アイテムの取得が可能。
  • IEnumerableとICollectionを継承している。

20171031ブクマ

azulitchi.hatenablog.jp

結合文字列を安全に合成する プレーンテキスト変換アプリ CiPT | Change into Plain Text

kafka.apache.org

qiita.com

www.lifehacker.jp

www.slideshare.net

Apache Kafkaに入門した | SOTA

www.publickey1.jp

www.slideshare.net

www.slideshare.net

www.ossnews.jp

広告を非表示にする

ASP.NET MVC:セキュリティ対応関連メモ

対応

1、クッキーの設定

Web.config
<system.web>
    <!-- 既存のコード -->
    <httpCookies httpOnlyCookies="true" requireSSL="true" />
</system.web>

SSL通信のときのみ、クッキーを有効にする

2、レスポンスヘッダーの設定

Web.config
<system.webServer>
    <!-- 既存のコード -->
    <httpProtocol>
      <customHeaders>
        <remove name="X-Powered-By" />
        <add name="X-Frame-Options" value="SAMEORIGIN" />
        <add name="X-XSS-Protection" value="1; mode=block" />
        <add name="X-Content-Type-Options" value="nosniff" /> 
      </customHeaders>
    </httpProtocol>
</system.webServer>
[X-Frame-Options:SAMEORIGIN]

iframeの制限を自身と生成元が同じフレーム内のみに制限

[X-XSS-Protection:1; mode=block]

XSSフィルターを有効とする

[X-Content-Type-Options:nosniff]

Webブラウザによる「Content-Type」の予測を回避し、ブラウザによる意図せぬ動きを回避

3、レスポンスヘッドのX-Frame-Optionsの自動出力の回避

ASP.NET MVC 5 では X-Frame-Options が自動で出力される時がある - しばやん雑記

[X-Frame-Options:SAMEORIGIN]を適用させたくない場合の設定(もちろん、2の[X-Frame-Options:SAMEORIGIN]設定がないことが前提。あると2の設定が優先される)

Global.asax.cs
using System.Web.Helpers;
using System.Security.Claims;

protected void Application_Start()
{
    // 既存コード
    AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
    AntiForgeryConfig.SuppressXFrameOptionsHeader = true;
}

4、ブラウザキャッシュの無効化

ActionFilterAttributeを継承するクラスのOnActionExecutedにキャッシュ無効化の記述を追記

FilterConfig.cs
public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new CacheAttribute());
    }
}
CacheAttribute.cs
public class CacheAttribute: ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        var response = filterContext.HttpContext.Response;
        response.Cache.SetCacheability(HttpCacheability.NoCache);

        base.OnActionExecuted(filterContext);
    }
}
Web.configで対応する場合(2と3を両方対応した例)
<httpProtocol>
  <customHeaders>
    <remove name="Cache-Control" />
    <remove name="X-Powered-By" />
    <add name="X-Frame-Options" value="SAMEORIGIN" />
    <add name="X-XSS-Protection" value="1; mode=block" />
    <add name="X-Content-Type-Options" value="nosniff" />
    <add name="Cache-Control" value="no-cache, no-store, must-revalidate" />
    <add name="Pragma" value="no-cache" />
  </customHeaders>
</httpProtocol>

確認

f:id:papamau:20171026153614p:plain

参考サイト

Cookie の仕様とセキュリティ

devcentral.f5.com

ASP.NETの状態管理:ビューステート/クッキー/セッション情報(2/3) - @IT

developer.mozilla.org

developer.mozilla.org

developer.mozilla.org

blog.shibayan.jp

developer.mozilla.org

qiita.com

OSコマンドインジェクション

SQL インジェクション攻撃とその対策

www.slideshare.net

www.websec-room.com

EntityFramework:ConnectionStringsのパスワードに特殊記号が含まれる場合

下記の手順でEntityFrameworkでMySQL接続が出来ていることを前提とする

pie001.hatenablog.com

pie001.hatenablog.com

パスワードに特殊記号が含まれる場合

既存のconnectionStrings

PW:abcefg

<connectionStrings>
  <add name="WpEntities" connectionString="metadata=res://*/EntityModels.WpModel.csdl|res://*/EntityModels.WpModel.ssdl|res://*/EntityModels.WpModel.msl;provider=MySql.Data.MySqlClient;provider connection string=&quot;server=localhost;user id=admin;password=abcefg;persistsecurityinfo=True;port=3306;database=wp01&quot;" providerName="System.Data.EntityClient" />
</connectionStrings>
上記からセキュリティ強化(?)のため、特殊記号を含めたパスワードに変更

PW:abc123efg;

<connectionStrings>
  <add name="WpEntities" connectionString="metadata=res://*/EntityModels.WpModel.csdl|res://*/EntityModels.WpModel.ssdl|res://*/EntityModels.WpModel.msl;provider=MySql.Data.MySqlClient;provider connection string=&quot;server=localhost;user id=admin;password=abc123efg;;persistsecurityinfo=True;port=3306;database=wp01&quot;" providerName="System.Data.EntityClient" />
</connectionStrings>

connectionStringsを変更した後、実行⇒早速エラー

f:id:papamau:20171026125304p:plain

f:id:papamau:20171026131020p:plain

エラー箇所
using (var db = new WpEntities())
{
    // クエリー ★エラー!
}

using (var db = new WpEntities())では問題ないが、クエリーを実行するとエラーになってしまう。

dbの設定内容を見てみるとConnectionStringの内容が以下になっていた。

"server=localhost;user id=admin;password=abc123efg;persistsecurityinfo=True;port=3306;database=wp01"

パスワードの最後の";"が消えてる…
因みにエラーには(using password: YES)になっていてパスワードは正しいんじゃないか?と最初勘違いしたけど、エラーメッセージに「using method 'mysql_native_password' failed 」と書いているので、つまりパスワードが間違ってた(特殊記号を認識できなくて正のパスワードとして認識できなかった)のが原因。

対策

1、今回の場合

パスワード部分を'(シングルクォーテーション)で囲む

<connectionStrings>
  <add name="WpEntities" connectionString="metadata=res://*/EntityModels.WpModel.csdl|res://*/EntityModels.WpModel.ssdl|res://*/EntityModels.WpModel.msl;provider=MySql.Data.MySqlClient;provider connection string=&quot;server=localhost;user id=admin;password='abc123efg;';persistsecurityinfo=True;port=3306;database=wp01&quot;" providerName="System.Data.EntityClient" />
</connectionStrings>

簡単すぎてちょっと虚しくなった(笑)

2、HTML特殊記号の場合

該当記号の書き方を調べたり

pst.co.jp

HTML特殊文字変換ツールを使って正しい書き方で記入する

tech-unlimited.com

参考

stackoverflow.com

20171020ブクマ

qiita.com

qiita.com

qiita.com

qiita.com

qiita.com

github.com

isucon.net

github.com

Front End Performance Checklist 2017

Front End Performance Checklist 2017 [PDF, Apple Pages] – Smashing Magazine

www.reddit.com

他人のサイトのアクセス数を確認 https://www.similarweb.com/ja

閲覧中のWebサイトで使われている技術を確認できるChrome拡張「Wappalyzer」のご紹介 qiita.com

今日からはじめるDocker - コンテナー仮想化の必要性を理解して、まず開発環境に導入してみよう! employment.en-japan.com

MANABIYA -teratail Developer Days- manabiya.tech

広告を非表示にする

ASP.NET Web API:Basic認証

.NET MVCのWeb APIBasic認証を適用する方法

f:id:papamau:20171018134917p:plain ↑の「Web API」を選択して作成したプロジェクトを基準とする。

docs.microsoft.com

MSDNに凄く詳しく書いているので、基本的にはそのままに良い。
以下、自分用のメモになります。

Web.config

<system.web>
    ...
    <authentication mode="Windows" />
</system.web>
<system.webServer>
    <modules>
        ...
        <add name="BasicAuthHttpModule" type="TestProject.Base.BasicAuthHttpModule, TestProject" />
    </modules>
</system.webServer>

BasicAuthHttpModule.cs

using System;
using System.Linq;
using System.Net.Http.Headers;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Web;
using TestProject.Base;

namespace TestProject.Base
{
    /// <summary>
    /// HTTP Basic 認証
    /// </summary>
    public class BasicAuthHttpModule : IHttpModule
    {
        private const string Realm = "Test APIs";

        public void Init(HttpApplication context)
        {
            // Register event handlers
            context.AuthenticateRequest += OnApplicationAuthenticateRequest;
            context.EndRequest += OnApplicationEndRequest;
        }

        private static void SetPrincipal(IPrincipal principal)
        {
            Thread.CurrentPrincipal = principal;
            if (HttpContext.Current != null)
            {
                HttpContext.Current.User = principal;
            }
        }

        private static void AuthenticateUser(string credentials)
        {
            try
            {
                var encoding = Encoding.GetEncoding("iso-8859-1");
                credentials = encoding.GetString(Convert.FromBase64String(credentials));

                int separator = credentials.IndexOf(':');
                string username = credentials.Substring(0, separator);
                string password = credentials.Substring(separator + 1);

                // CheckPassword内でDBの値と比較するなりして認証可否を確認する
                if (CheckPassword(name, password))
                {
                    // 認証後の必要処理を行う
                    var identity = new GenericIdentity(name);
                    SetPrincipal(new GenericPrincipal(identity, null));
                }
                else
                {
                    // Invalid username or password.
                    HttpContext.Current.Response.StatusCode = 401;
                }
            }
            catch (FormatException)
            {
                HttpContext.Current.Response.StatusCode = 401;
            }
        }

        private static void OnApplicationAuthenticateRequest(object sender, EventArgs e)
        {
            var request = HttpContext.Current.Request;
            var authHeader = request.Headers["Authorization"];
            if (authHeader != null)
            {
                var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);

                // RFC 2617 sec 1.2, "scheme" name is case-insensitive
                if (authHeaderVal.Scheme.Equals("basic", StringComparison.OrdinalIgnoreCase) && authHeaderVal.Parameter != null)
                {
                    AuthenticateUser(authHeaderVal.Parameter);
                    //if (!AuthenticateUser(authHeaderVal.Parameter))
                    //{
                    //    HttpContext.Current.Response.StatusCode = 401;
                    //}
                }
            }
        }

        // If the request was unauthorized, add the WWW-Authenticate header 
        // to the response.
        private static void OnApplicationEndRequest(object sender, EventArgs e)
        {
            var response = HttpContext.Current.Response;
            if (response.StatusCode == 401)
            {
                response.Headers.Add("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", Realm));
            }
        }

        public void Dispose()
        {
        }
    }
}

TestController.cs

[Authorize]
public class TestController : ApiController

C#:Json内のhtmlタグのエスケープについて

1、JavaScriptSerializer:string ⇒ JSON変換

using System.Web.Script.Serialization;

var json = new JavaScriptSerializer().Serialize("A->B"); // "\"A-\\u003eB\"

HTMLタグのエスケープ

JavaScriptSerializerを利用してJSONに変換する場合、HTMLタグは\u形式のユニコードエスケープされる。
そのため、JSON内のHTMLタグをそのまま使うことが出来ず、"\u003e"⇒">"な感じで再度変換してあげる必要がある。

stackoverflow.com

stackoverflow.com

2、 Json.NET:string ⇒ JSON変換

using Newtonsoft.Json;

var json = JsonConvert.SerializeObject("A->B") // "\"A->B\""

HTMLタグをそのままにしてJSONに変換したい場合はJson.NETを使う。