CubeICE の Zip Slip 脆弱性に関する調査報告

先ほど「Zip Slip」と命名された圧縮・解凍処理に関する脆弱性の情報を目にしました。

この記事では、Zip Slip の概要および CubeICE における関連部分の処理内容について記載します。尚、CubeICE に関しては、少なくとも 0.8.0β 以降であれば、Zip Slip 脆弱性の原因とされる不都合はない 事を Snyk によって公開されている サンプルファイル を利用したテスト等によって確認しています。テストコードは ArchiveReaderTest を参照下さい。また、これに合わせて、CubeICE 0.8.0β 未満をご利用のユーザは、可能な限り最新版のご利用をお願いします(参考:圧縮・解凍ソフト CubeICE をゼロから改修)。

Zip Slip 確認用のサンプルファイルを CubeICE で解凍した結果

Zip Slip 脆弱性の概要

Zip Slip は、圧縮ファイルのファイルリスト(ヘッダ部分)に ".." (double-dot) を含むパスが存在する場合、親ディレクトリに存在するファイルがユーザの意図しない形でコピーまたは上書きされる directory traversal と呼ばれる脆弱性の一種のようです。例えば、Zip Slip の解説サイトでは tmp/evil.sh と言うパスの前に大量の ".." を付記しておく事で、/tmp ディレクトリに悪意のあるファイルを作成する手順が示されています。

In the example below, we can see the contents of a zip file. It has two files, a good.sh file which would be extracted into the target directory and an evil.sh file which is trying to traverse up the directory tree to hit the root and then add a file into the tmp directory. When you attempt to cd .. in the root directory, you still find yourself in the root directory, so a malicious path could contain many levels of ../ to stand a better chance of reaching the root directory, before trying to traverse to sensitive files.

5 Tue Jun 5 11:04:29 BST 2018 good.sh
20 Tue Jun 5 11:04:42 BST 2018 ../../../../../../../../tmp/evil.sh

Zip Slip Vulnerability

圧縮ファイルのファイルリストに含まれる ".." を処理する際には注意が必要である、と言う問題自体は古くから認識されています。例えば、先日 iOSAndroid 上の多数のアプリに「ZipperDown」と命名された脆弱性が存在すると報道されましたが、これも directory traversal に起因するものだったようです。

しかし、今回の脆弱性に関しても、ファイルリストに含まれるパスをそのまま扱っている事例が思いの外多かったのか Zip Slip の影響を受けるライブラリ もかなりの数に上っています。Snyk では、例えば下記のように、ライブラリから取得出来た名前(相対パス)をそのまま結合するようなコードが含まれている場合、特に注意を要する旨が記載されています。

Enumeration<ZipEntry> entries = zip.getEntries();
while (entries.hasMoreElements()) {
    ZipEntry e = entries.nextElement();
    File f = new File(destinationDir, e.getName());
    InputStream input = zip.getInputStream(e);
    IOUtils.copy(input, write(f));
}

CubeICE における圧縮ファイル中のパスの扱い

CubeICE では、圧縮ファイルのヘッダ情報から取得したパスに対して PathFilter と言う自作クラスを介してアクセスしています。PathFilter は、指定されたパスをディレクトリ単位で分割し、それぞれのファイル名またはディレクトリ名に対して下記のようなチェックを実行します。また、CubeICE では 圧縮・解凍時に特定のファイルまたはディレクトリをフィルタリングする機能を提供していますので、その判定も PathFilter が担っています。

  • カレントディレクトリを表す "." (single-dot) が含まれているかどうか
  • ディレクトリを表す ".." (double-dot) が含まれているかどうか
  • ドライブ文字 (drive-letter) が含まれているかどうか
  • UNC パスを表す接頭辞 "\\" が含まれているかどうか
  • サービス機能の不活性化を表す接頭辞 "\\?\" が含まれているかどうか
  • ファイル名またはディレクトリ名の一部に使用不可能な記号が含まれているかどうか
  • ファイル名またはディレクトリ名に Windows で予約済みの名前が存在するかどうか

この PathFilter を実際に利用しているコードが下記 (ArchiveItemController) になります。ただし、これは圧縮ファイルの 1 項目を表す ArchiveItem クラスの内部実装なので、普段はその存在を意識する事はありません。

_filter = new PathFilter(RawName)
{
    AllowParentDirectory  = false,
    AllowDriveLetter      = false,
    AllowCurrentDirectory = false,
    AllowInactivation     = false,
    AllowUnc              = false,
};

src.FullName = _filter.EscapedPath;

上記の各種 AllowXxx プロパティでは、対応するシンボル(single-dot, double-dot, drive-letter, ...) の存在を許容するかどうかを設定しています。PathFilter は許容しない場合には該当のシンボルを除去するため、結果として CubeICE ではこれらの特殊なシンボルを全て無視します。例えば、脆弱性の解説において例示されていた "../../../../../../../../tmp/evil.sh" と言うパスは、単に "tmp/evil.sh" として扱います。この処理は、基本となるライブラリ部分で強制的に実行しているため、Readme に記載している下記のサンプルコードにおいても、今回の脆弱性の影響を受ける事はありません。*1

// Set password directly or using Query<string>
var password = new Cube.Query<string>(e => e.Result = "password");
using (var reader = new ArchiveReader(@"path\to\archive", password))
{
    reader.Extract(@"path\to\directory");
}

*1:もっとも、現時点では、System.FileSystem.SevenZip ライブラリ自体はまだ NuGet に登録していないため、この情報が参考になる人がいるのかは不明ですが……

CubeICE とカスタマイズ版 7-Zip ライブラリ

本日、CubeICE 0.9.0 β をリリースしました。修正内容は リリースノート に任せるとして、この記事では CubeICE で利用している 7-Zip のカスタマイズ版ライブラリの概要と、7-Zip ライブラリのみを更新する方法について記述します。

概要

CubeICE は、実際の圧縮・解凍処理を全て 7-Zip に頼った実装となっていますが、オリジナルの 7-Zip ライブラリ (7z.dll) に対して文字コードの推測処理を追加し、Unicode 文字セット*1 でビルドするようにカスタマイズしています。このカスタマイズ版 7-ZipソースコードGitHub より、ビルドした結果に関しては AppVeyor より取得する事ができます。

今回、この記事を公開しようと思った動機は、CubeICE のバージョンアップが間に合わない時に 7-Zip だけでも更新できる方法を公開しておいた方が良いと思ったためでした。先日、「7-Zip」に任意コード実行の脆弱性、修正版の v18.05 が公開 と言う記事でも報道された通り、2018/04/30 に公開された 7-Zip 18.05 には脆弱性に対する修正も含まれていましたが、諸々の都合で 7-Zip の該当バージョンを適用した CubeICE がリリースされるまでに 3 週間強のタイムラグが発生する事となりました。

カスタマイズ版 7-Zip のオリジナル版への追随に関しては、圧縮・解凍ソフト CubeICE をゼロから改修 した段階で楽に実現できるように改善されたため、多くの場合で、CubeICE のバージョンアップのかなり前の段階で利用可能な状態となります。そのため、7-Zip 由来の脆弱性等に関しては、これらのライブラリを差し換える事で CubeICE のバージョンアップ前であっても対応する事ができます。

カスタマイズ版 7-Zip の差し換え方法

CubeICE のバージョン確認

まず、CubeICE のバージョンを確認して下さい。CubeICE のバージョンは「CubeICE 設定」の「バージョン情報」タブで確認する事ができます。この時、バージョンが 0.8.0β 未満(0.7.3β や 0.6.8β など)の場合は CubeICE を最新版にアップデートして下さい。CubeICE は 0.8.0β にて大幅な変更が加えられていますので、それ以前のバージョンには適応できない可能性があります。バージョンが問題なければ、その右隣に記述されている文字列(x86 または x64)を覚えておいて下さい。

AppVeyor の cube-soft/7z プロジェクト

次に、AppVeyor の cube-soft/7z プロジェクト へ移動します。ここで、先ほどの文字列が x86 だった場合は「Platform: Win32」のリンク、x64 の場合は「Platform: x64」のリンクをクリックします。そうすると、中段の右側に「ARTIFACTS」と言うリンクがありますので、クリック後に表示される Zip ファイルをダウンロードして下さい。ダウンロード終了後、解凍したフォルダにある 7z.dll と 7z.sfx のファイルを CubeICE のインストールフォルダ(初期設定では C:\Program Files\CubeICE)にコピーして差し換えると完了です。

*1:Visual C++ の設定には、Unicode 文字セットでビルドする方法とマルチバイト文字セットでビルドする方法の 2 種類が提供されています。

Windows アプリ開発で利用している Web サービス

近年は GitHub を始めとした Version Control Systems (VCS) のホスティングサービスと連携する形で、プログラミングやソフトウェア開発に関する様々な Web サービスが提供されています。私は専ら Windows のデスクトップ・アプリケーションを開発していますが、この領域においても便利な Web サービスが数多く登場してきました。そこで、この記事では、私が Windows アプリを開発する際に利用している Web サービス (AppVeyor, Codecov, Codacy) について纏めていこうと思います。

AppVeyor

AppVeyorWindows サーバ上で提供される継続的インテグレーション (CI: Continuous Integration) の Web サービスです。CI サービスとしては Travis CICircle CI などが有名ですが、AppVeyor は Windows .NET Framework、Visual Studio などのサポートが充実している事もあり、Windows アプリやサービスの開発者を中心に利用者を増やしているようです。

私が実際に CI と言うものに触れたのは AppVeyor が初めてでしたが、利用して感じた利点は主に以下の 2 つです。

  • ビルド結果のスナップショットが自動的に保存されていく
  • ローカル開発環境とは異なる環境でビルドおよびテストを実行する事ができる

VCS と言う概念が普及した事もあり、ソースコードに関しては私も長らく Git を用いてバージョン管理を行っています。しかし、最終的なビルド結果に関しては、残念ながら管理がおざなりになる傾向にありました。そのため、何らかの理由で以前のバージョン結果が必要になった時、特定のタグやコミットを基にして再度ビルドしなければならない事も多く、複数のリポジトリが関係する場合には必要な状態に戻しきれているのか不安な事もありました。AppVeyor は、ビルド結果をダウンロード可能な形で残す事ができるため、これらの手戻り作業が発生せず、必要な時点のスナップショットを確実に取得できるのは大きな利点だと感じます。

また、私の開発環境は、2 台のデスクトップ PC と 1 台のノート PC と言う 3 台構成となっていますが、これらの環境は概ね同じ構成となっているのでローカル環境では気付かなかった不都合が発生する事があります。この問題を幾らか改善する方法の一つとして、AppVeyor 上での実行が役に立っていると実感するようになりました。例えば、(副次的ではありますが)言語設定やタイムゾーンがローカル環境とは異なる設定となっている都合上、その辺りに起因するケアレスミスを手軽に事前確認する手段としても機能しています。

依存関係の解決

ここからは、AppVeyor の設定ファイルを記述する際に躓いた事項について、いくつか記載していきます。尚、これらのほとんどは CubeICE の AppVeyor.yml で問題となった事なので、リンク先の設定ファイルが具体例として良いかもしれません。

まず最初の課題は、ビルド時の依存関係の解決でした。AppVeyor 上でビルドする時、ビルド対象となるプロジェクトが NuGet で公開されているパッケージのみに依存しているのであれば楽なのですが、そうではない場合には少し工夫が必要となります。私が直面した問題は、以下の 2 点でした。

  • プライベートまたは公開前の NuGet パッケージに依存する場合
  • VC++ で記述されているような非マネージ・ライブラリに依存する場合

CubeICECubeRSS Reader が依存している自作ライブラリは、最近まで NuGet 上には公開せずプライベートな状態が続いていました。*1 また、現在においても、これらのプロジェクトの master ブランチは公開前のバージョンを参照している事があるため、何も対策せずにビルドするとエラーが発生します。

この問題に対しては、依存する自作ライブラリも含めて AppVeyor 上で管理する事で解決を図りました。AppVeyor は毎回 NuGet パッケージを生成し、そのパッケージには静的な URL でアクセス可能です。そこで、下記のように NuGet のソースとしてそれらを追加する事で、プライベートな NuGet パッケージを参照する事ができるようになります。

- nuget sources add -name Cube.Core -source https://ci.appveyor.com/nuget/cube.core
- nuget sources add -name Cube.FileSystem -source https://ci.appveyor.com/nuget/cube.filesystem
- nuget sources add -name Cube.Images -source https://ci.appveyor.com/nuget/cube.images
- nuget sources add -name Cube.Forms -source https://ci.appveyor.com/nuget/cube.forms
- nuget restore Cube.FileSystem.SevenZip.Ice.sln

次に非マネージ・ライブラリに依存している場合です。これは、自力でダウンロードして出力ディレクトリにコピーする方法で解決を図りました。例えば、CubeICE は 7z.dll と言う 7-Zip のライブラリ (正確には カスタマイズ版) に依存していますが、このライブラリをダウンロードして展開する設定は下記のようになります。

- ps: Start-FileDownload https://ci.appveyor.com/api/projects/clown/7z/artifacts/7z-x64.zip?job=Platform:+x64
- 7z x -o"Applications\Ice\Progress\bin\Release" 7z-x64.zip

尚、カスタマイズ版の 7-Zip ライブラリも AppVeyor で管理している都合上、上記ではその生成結果をダウンロードしています。もし AppVeyor 上で完結できない場合であっても、同様の方法で必要なライブラリをダウンロードして展開する事で、多くのケースは解決できるのではないかと思います。

最終成果物 (Artifacts) の整形

AppVeyor はビルド結果などの最終成果物を Artifacts と呼んでおり、これらは特定の URL からダウンロード可能となります。この Artifacts に関する設定のうち、NuGet パッケージについては "publish_nuget: true" と言う記述だけで自動的に生成してくれますが、それ以外のものについては "artifacts" の項目に記述する必要があります。この項目は、単に生成する事だけを考えるのであれば "path" にビルドの出力ディレクトリを記述すれば OK です。しかし、個人的にはダウンロード用の URL が少し不格好になるのが気になり、何とかならないかとドキュメント等で解決方法を模索していました。

Artifacts の整形

この問題に対しては、最終的には "after_build" の項目で好みの形になるように整形する方法を採用しました。例えば、CubeRSS Reader のメインプログラムを CubeRssReader.zip と言う形で Artifacts に保存する場合、以下のように記述します。

after_build:
  - xcopy /Y /I Applications\Rss\Reader\bin\Release CubeRssReader
artifacts:
  - path: CubeRssReader

尚、場合によっては "x86" や "x64" のように、設定によって動的に変更される値が必要になりますが、AppVeyor において利用可能なこれらの値は Environment variables に記載されています。例えば、"x64" と言う値が必要な場合は %PLATFORM% と記述します。

複数ブランチを個別に CI 管理

全てのブランチを単一の AppVeyor プロジェクトで管理するのであれば良いのですが、場合によってはブランチ毎に個別に管理したい時もあります。例えば、CubeRSS Reader では WebView に Chrome ブラウザを利用したもの (chrome ブランチ) を実験的に公開していますが、これを AppVeyor 上でも master ブランチとは区別して管理したいと思うようになりました。

複数ブランチを個別に CI 管理

この課題には、AppVeyor 上で GitHub(または類似の VCS ホスティングサービス)の同じリポジトリを参照するプロジェクトを複数個作成し、それぞれの設定ファイルの "branches" で対象とするブランチを絞る事で対応するようです。しかし、この場合でも意図した動作になるように設定するのは意外と難しく、最終的には以下のような形になりました。

  1. master ブランチの設定ファイル (AppVeyor.yml) とは別に、chrome ブランチ専用の設定ファイルを作成する (AppVeyor.Chrome.yml)。そして、AppVeyor.yml の "branches" には master、AppVeyor.Chrome.yml には chrome ブランチのみを対象とするように記述する。
  2. AppVeyor の各プロジェクトの Settings で、"Custom configuration .yml file name" の項目に対応するブランチの設定ファイル名をそれぞれ入力する。
  3. chrome ブランチ用プロジェクトの Settings で、"Branches to build" の項目を "On branches specified below" に選択し、その下に chrome と入力する。

問題となったのは 3. に記載した部分です。AppVeyor は GitHub に push したタイミングで、指定された設定ファイルに従って実行するかどうかを決定します。この時、master ブランチには AppVeyor.Chrome.yml が存在しないため、chrome ブランチ用のプロジェクトでは初期設定が利用されます。初期設定では全てのブランチで CI を実行する事になっているので、意図しないブランチの CI 実行結果も反映される事となりました。この誤動作を防止するために、プロジェクトの Settings でも chrome ブランチ以外の実行を防止するように設定しています。

Codecov

Codecov

Codecov は、GitHub などにホスティングされているリポジトリのテストカバレッジを可視化するための Web サービスです。Codecov 自体は、何らかのユニットテストが実行された結果を表すファイルを解析して表示するものであるため、多くの場合 CI サービスと連携して利用されます。Windows アプリ開発の場合は前述した AppVeyor 上でユニットテストを実行し、その結果をファイルに出力して Codecov に送信します。

Codecov を利用するようになって最も良いと感じているのは、プログラムを 行単位で テストが実行されたかどうかを確認する事ができると言う点です。例えば、引数を伴うメソッドを実装する場合、最初に引数の null チェックを記述しがちですが、Codecov 上で確認すると、該当の行が黄色(C1 カバレッジが未達成)のままな事があります。

この時、まず最初に検討するのはテスト不足ですが、同時に「この null チェックは不要なのではないか?」と言う可能性についても検討します。そして、呼び出し元なども確認した結果、該当のチェックが不要であると確認できた場合には、単純に消去するか、もしくは assert 文に置換します。このように、自分のプログラムを行単位でテストが実行されているかどうかを定期的に確認すると言う行為が、セルフ・コードレビューのような機能も果たす事が分かりました。

カバレッジの数値との付き合い方

カバレッジの数値、例えば 80% や 100% のような値をどう捉えるかに関しては、当初よりもかなりポジティブな印象を抱いています。例えば、「enum に対応する文字列を取得する」ような単純なメソッドのテストコードに対しては、長らく「このテストに、カバレッジの数値を上げる以外の意味があるのだろうか?」と言う疑問を抱いていました。しかし、これらのテストコードによって、リファクタリング時の Typo による思わぬバグを早期に発見できた言う経験が何度もあり、一見すると無駄に見えるテストの重要性を実感するようになりました。

カバレッジの数値を上げるためだけの近視眼的なテストコードを記述する事によって、それよりも重要なテストコードを見逃すのではないかと言う不安は依然としてあります。ただ最近は、ある程度は仕方がないと割り切り、以下のような指針で実装およびテストコードの記述を行っています。

  1. 初期リリースまでは、取り合えずカバレッジの数値(80%~90% 程度)を指標としてテストコードを記述する。この結果、初期リリース時点では、正常ケースおよび容易に予想可能な異常ケースのテストに留まる。
  2. リリース後に何らかの不都合が発覚した場合、必ず最初に該当の不都合が再現するテストコードを記述する。そして、テストを実行してレッド・シグナルを確認する。
  3. 該当部分の実装コードを修正し、テストを実行してグリーン・シグナルを確認する。

このサイクルによって、完全ではないにしても「少しずつだが、良くなってはいる」事を実感できるのは、テストコードを含めた保守を続けていく、あるいは習慣化する上でプラスに働いていると思います。

AppVeyor との連携設定

前述したように、Codecov は何らかの CI サービスと連携して利用する事がほとんどです。ここでは、AppVeyor との連携方法について記載します。AppVeyor では、まず始めに "test_script" の項目でテストを実行します。私の場合、ユニットテストフレームワークNUnitカバレッジ計測ツールは OpenCover を利用しており、具体的な記述例は下記のようになります。

test_script:
  - >
    packages\OpenCover.4.6.519\tools\OpenCover.Console.exe
    -register:user
    -target:nunit3-console.exe
    -targetargs:Cube.FileSystem.SevenZip.App.Ice.Tests.dll
    -targetdir:Applications\Ice\Tests\bin\Release
    -returntargetcode
    -hideskipped:All
    -output:CoverResult.xml
    -filter:"+[*]* -[*]*NativeMethods -[*]*Properties.* -[*]*.Program"

尚、OpenCover の実行プログラムは NuGet 経由で取得するため、テスト対象となるプロジェクトの packages.config に OpenCover を含める必要があります。また、複数のテストを実行する場合 -mergeoutput オプションを記述する事で結果を 1 つのファイルに纏める事ができます。

OpenCover の実行で躓いた点は -returntargetcode オプションでした。このオプションがない場合、テストが失敗した場合であっても正常終了したと見なされるようになります。その結果、不完全な結果が Codecov に送信されてカバレッジの推移が見づらくなると言う問題が発生しました。これに対して -returntargetcode オプションを指定した場合、テストに失敗したタイミングで AppVeyor が実行を中止します。

after_test:
  - "SET PATH=C:\\Python34;C:\\Python34\\Scripts;%PATH%"
  - pip install codecov
  - codecov -f CoverResult.xml

テストの終了結果を Codecov に送信する設定は上記のようになります。Codecov は、プロジェクト毎にアップロード用 API key を割り当てるのですが、AppVeyor 経由だと API key は必要ないようです(ローカル環境からアップロードしようとした場合は必要)。

Codacy

Codacy

Codacy は、コードレビューの自動化 Web サービスです。GitHub に push したタイミングで対象となるリポジトリのプログラムに対して何らかの静的解析が実行され、その結果を Web 上で閲覧する事ができます。Supported Languages によると、対応しているものは ScalaJavaJavaScriptPythonRubyPHP を始めとした 14 種類で、この中に C# も含まれています。また、Codacy はカバレッジのレポート機能も有していますが、現状では残念ながら C# のプロジェクトには適用できませんでした。将来的には、Codecov で行っている事も Codacy に統合できるかもしれません。

私が Codacy の存在を知ったのは数ヶ月前の事で、まだそこまで使いこなせている訳ではないのですが、なかなか良い感触を得たため、自分のプロジェクトに対して順次適用しています。Codecov の項目でも少しだけ触れましたが、ほとんど 1 人で開発を行っているとコードレビューを行う人がそもそも存在しないため、定期的なセルフ・コードレビューを意識する必要があります。Codacy は、この課題を補う方法の一つとして機能していると感じます。

Codacy は解析の結果、問題のある項目を Issue として登録します。そして、プログラマがその Issue を解決する方法としては、以下の 4 つが挙げられます。

  • プログラムを修正する
  • 該当の Issue を無視する (Ignore issue)
  • 登録された Issue を特定するのに使用されたルールを無視する (Remove pattern)
  • 該当ファイルの全ての Issue を無視する (Ignore file)

基本原則としては、プログラムを修正する事によって Issue の解決を図るべきとは思います。ただ、実際にやっていると様々な理由で、それだけでは行き詰まる事があるのも事実です。ここでは、私がこれまで「無視」を選択した Issue について、いくつか記録を残しておこうと思います。

Unused 系の Issue をどう扱うか

私が Codacy を数ヶ月利用した中で、最も判断に迷うのが Unused 系の Issue の扱いについてでした。Codacy は、未使用の変数やメソッドを発見した場合、それを Issue に追加します。これ自体は良い事で可能な限り修正(削除)すべきですが、問題になったのはその精度でした。

私も Issue が登録された場合、まずは自分の側に問題があると考えて解決方法を模索しますが、Unused 系に関しては、現時点の自分の知識ではどう考えても誤動作ではないかと思われる Issue が大量に登録されます。代表的なものは以下の 3 点です。

  • public な class の public なプロパティであり、該当のプロパティを使用しているテストコード等が存在するにも関わらず "Remove the unused private property" と言う Issue が登録されてしまう
  • 定義した次の行に変数を使用している記述があるにも関わらず "Remove this unused 'foo' local variable" と言う Issue が登録されてしまう
  • イベントを定義すると、同クラス内で Invoke する記述が存在し、該当イベントを利用しているテストコード等が存在するにも関わらず "Events should be invoked" と言う Issue が登録されてしまう

これらに関しては、今のところ「十分に検討したが、やはり誤動作だろう」と思ったものについては個別に Ignore issue を選択しています。C# の解析には Sonar C# が用いられているとの事なので、余裕があればそちらの方も少し見てみようかと思います。

その他に無視した Issue 一覧

上記以外で無視している Issue (Remove pattern) は以下の通りです。これらに関しては、音楽性の違いに依るものもあるので、無効にせず修正した方が良いと感じる人もいるかもしれません。

  • Empty "default" clauses should be removed
    "default: break;" と言う記述があると登録される Issue です。元々、switch 文の処理のない default 句は書かないようにしていたのですが、default 句は必ず記述する旨の Issue が登録されたので対応した所、今度は上記の Issue が登録されてしまいました。現状では、こちらの Issue を無視しています。
  • Control structures should use curly braces
    if 文や while 文などのブロック部分には必ず中括弧を記述すべきだと言う Issue です。個人的には、条件文とブロック部分の間に改行を挿入するスタイルは予期せぬバグを埋め込む可能性があり NG ですが、「1 行で書ききれるのであれば、中括弧は省略しても良い」と言う思想なので(if (condition) { return; } とは書きたくない)このIssue は無視しています。
  • Members should not be initialized to default values
    private object _member = null; のような記述はやめろと言う Issue です。null に関しては Issue に従って削除していますが、bool や int 等に関しては「その値をソースコード上で明示しておく事に意味がある」と感じる事も多いので、ケース・バイ・ケースで個別に無視しています。
  • Methods and properties that don't access instance data should be static
    あるクラスのメソッドが、そのクラスの状態にアクセスしないのであれば static にすべきだと言う Issue です。プログラムの見やすさを改善する意味で作成する private メソッドで指摘される事が多いようです。指摘内容は分からなくもないのですが、private メソッドはちょっとした修正で状態にアクセスする必要が出てくる事も多いので、この Issue は無視しています。

以上、私が現在の開発で利用している Web サービスの紹介でした。

*1:クラスやメソッドなどの公開インターフェースに対して破壊的な変更をまだまだ行っていたので、公開版とするのは時期尚早と考えていました。