誤って削除したSDカード上の画像ファイルを復元

先日、某行政のサーバーのHDDがヤフーオークションに転売され、購入した方がデータ復元したところその行政が管理する個人情報が見つかる(復元できた)という事件が起きました。

近年HDD、SSD、SDカードなど多くのストレージメディア・媒体があるわけですが、たとえばFAT系のファイルシステムでは、単純なファイル削除を行った場合に、そのファイルのデータをビット単位で完全に削除している訳ではありません。そのファイルの「管理情報」(正確にはDIR_NAMEフィールドの0バイト)にファイルが削除されたというフラグ(例えば0x05と設定)を立てることで「そのファイルは削除したこととする」というルールとし、そのファイルの「本体データ」は自体は削除されていません。OSやカメラなどからはこのフラグ処理でファイルは見かけ上認識されなくなります。その為、ファイルの復元とは、このDIR_NAMEフィールドの0バイトを元に戻してあげれば、OSからファイルが再認識できるようになります。ただし、削除後に新しいデータを書き込んでしまい、復元したかったファイルが保存されていた領域に新たなデータが書き込まれてしまいますと復元は技術的に不可能となります。そういう意味でも、誤って削除した場合にはそのドライブ・SDカードなどに新しい書き込みをしないというのが鉄則です。

今回こんな記事を書いているのは、ちょっとした凡ミスで撮影画像ファイルが消えてしまいまして、その後無事復元できたので紹介します。

<参考>
ファイルシステムに興味があれば、SDカードなどで一般的に使われているファイルシステムのexFATが2019年にMicrosoft社から仕様が公開されたのでご覧ください。

参考1) exFAT file system specification – Win32 apps | Microsoft Docs
参考2) FATファイルシステムのしくみと操作法 (ELM by ChaN)

<経緯・現象> 
撮影してきたカメラからSDカードを取りだし、USBカードリーダー経由でWindows 10 PCにファイルを転送する際に、少し訳ありで転送先の保存に失敗しました。本来SDカードからの大切な画像データの転送は

1)SDカードの画像から、転送先に「コピー」
2)転送先でのデータ転送の「成否の確認」
3)2)の確認後、SDカードの画像を「削除」。
(*Windows等のファイル削除ではなく、カメラ内機能でのフォーマットが良いと思う)

とするのが必要なフローですが、ものぐさで、SDカードから転送先へ「移動」を選び、訳ありの理由で転送先での保存に失敗しました。その為、SDカード上での画像ファイルも失われたという状況でした。

<復元作業>
復元に際して、ファイルシステムを理解して削除フラグを変えるソフトを自作してもよいのですが、巷にはいくらでもソフトが溢れているのでそれを利用します。検索したら一番最初に出てきたEaseUS Data Recovery Wizardを使ってみます。この手のソフトはフリー版と有償版があり、フリー版は復元ファイル数に制限があるか、復元できそうという結果だけわかり復元するには有償版へというソフトが多い。とりあえず2GBまではFree版で使えるということで使って見ました。はっきり言って使い方は説明する必要もなく直感で分かると思います。

SDカード( J:ドライブ)をクリックしてスキャンするだけ。
削除された4つのファイルがすぐに検出され、「削除されたファイル(4)」として表示されるので、選択して右下の「リカバリー」ボタンを押し、復元保存先を指定するだけです。
またSDカード全体のスキャン完了を待たずして復元作業ができるのでサクサク復元できました。
*言うまでもなく復元保存先はSDカード以外を選択すべきです。
こんな感じで4つの誤って削除した画像(JPEG + Fujifilm RAW)が復元。
アイコンのサムネイルが表示されているように全くファイルは壊れていませんでした。

上記の通りWindowsのエクスプローラーで削除(または移動による削除)では、直後に実行すればほぼ確実に復元できそうな感じです。12枚ほど削除しては復元するを繰り返してみましたが100%復元できました。SDカード全体とか多量のファイルを復元する際には、有償版(Pro)を購入する必要があるかもしれません。

次におまけの実験で、カメラの画像再生での消去を試してみました。

カメラ(Fuji X-T3)の機能として画像削除
結果としては、JPEGは復元可能、RAW(Fujifilm RAF)は復元不可でした。

何回やっても、RAWの復元は失敗でした。これは、カメラ(X-T3)側のファイル削除が何か特殊なのか、原因はわかりません。一方で、カメラ側で画像を削除するという行為自体、基本的には避けるべきだと思います。ピンボケ、手ぶれなど明らかに撮影に失敗することもあるかと思いますが、今やSDカード等のメモリも大容量で千枚単位で撮れると思いますので、失敗しても現場でカメラ機能では削除せず、あとでPC等で消せば良いのです。上記の通り復元にも失敗するケースもありますし、手元の操作ミスで成功した写真も誤って消してしまう可能性もあるので、そういう意味でもカメラ側で画像を削除するのは避けるべきだと思います。

<まとめ>
ファイル復元ソフトを使えば、大方のファイルは削除直後なら復元できる。
・カメラ内機能での削除はRAWファイルは復元できなかったが、そもそもカメラ側で画像は消すべきではない。
・SDカードからPCへの転送は、コピー → 転送先確認 → 削除のフローを行った方が良い。プロなんかは、転送先で更にバックアップをとってからSDカード等の画像を消すという人も多いでしょうね。
・あと、何かあったときに焦らないように削除して復元するというフローを1度試しておくと良いかと思います。

Share
Chrome ver58以降の自己署名証明書(Self-signed certificate)のエラー対策 (net::ERR_CERT_COMMON_NAME_INVALID) : SAN追加

自己署名証明書(Self-signed certificate = いわゆるオレオレ証明書)を使ったWeb ServerにChromeの最新版(Ver 58 : 2017/04/28現在)でアクセスすると
`net::ERR_CERT_COMMON_NAME_INVALID`というエラーが出て接続ができなくなりました。その対策です。いろいろ情報は出ていますが、少数派と思われるWindows Server CAによる署名では情報が少なかったのでシェア。

時代の流れで常時TLSが一般的になりつつあり、LAN内でもWindows Server 2012 R2の証明機関(CA)機能による自己署名証明書を発行し、同じくLAN内のWeb Server (Apache2 on Linux)で利用していましたが、先週からChromeでエラーが出るようになりました。いろいろ調べてみると、最新版のChrome ver58以降から、Self-signedの証明書はエラーを出すらしく、いろいろ海外のサイト等で議論されていました。
私は、証明書(X.509v3)にマルチドメインなどに使うSAN (Subject Alternative Name) =日本語で「サブジェクト代替名」を拡張領域(フィールド)に追加し、そこにホスト名等を埋め込むことで対応することができました。この部分は、RFC2818で推奨されているようです。

<該当部分引用:from RFC2818>

If a subjectAltName extension of type dNSName is present, that MUST
be used as the identity. Otherwise, the (most specific) Common Name
field in the Subject field of the certificate MUST be used. Although
the use of the Common Name is existing practice, it is deprecated and
Certification Authorities are encouraged to use the dNSName instead.

<環境条件>
C1) LAN内オンプレのWindows Server 2012 R2にcertsrv (証明機関)および、IIS上にウェブサービスの`Microsoft Active Directory 証明書サービス`(以下Web CertSrv)が起動しているものとします。
C2) LAN内ウェブサーバーは、Apache2 (on CentOS7)とします。
C3) 証明書は、ECCなんぞハイカラなモノは避けて、RSA2048bitで保守的に。

<解説>
エラーが出る前までは、Web ServerのLinux上のOpenSSLでCSRを発行し、それをWindows ServerのWeb CertSrvで署名をして証明書をダウンロードし、Apacheのssl.confに追加していました。いろいろな海外サイトでは、Linuxサーバーの証明機関で自己署名をしているので、それでも完結(解決)できるはずですが、今回はWindows Server 2012 R2にリモートデスクトップで入り、その中にWindows版のOpenSSLを使ってCSRを作り、Web CertSrvで署名をしました。

<手順>
P1) Windows Server 2012 R2に管理者権限のあるアカウントでリモートログイン

P2) 管理者コマンドプロンプトにて、証明書へのカスタム属性対応を設定します。
c:\> certutil -setreg policy\EditFlags +EDITF_ATTRIBUTESUBJECTALTNAME2

P3) 証明機関サービスを再起動
c:\> net stop certsvc
c:\> net start certsvc
→これで、内部CAが、SANの拡張領域に対応できます。

P4) Windows版OpenSSLのダウンロードとインストール:Shining Light Productions – Win32 OpenSSL
* 2017/04/28現在:Win32OpenSSL-1_1_0e.exe (WIN32 OpenSSL v1.1.0e)を入れました。これを書いていて気がついたのですがWin64の64bit版もあったのですね・・。Windows Server 2012 R2自体が64bit版なので、Win64を使うべきかと思います。私は気がつかずWin32版で行いました。C:\OpenSSL-Win32にインストール

P5) “C:\OpenSSL-Win32\bin\openssl.cfg”のコンフィグファイルを編集します。
[ v3_req ]という箇所を見つけて、以下の通り編集します。

[ v3_req ]
# Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]

DNS.1 = hoge.abc.yourdomain.com
DNS.2 = hoge2.abc.yourdomain.com
DNS.3 = abc.yourdomain.com

SANに追加したいホスト名・ドメインを追加して行きます。SANはマルチドメイン用のフィールドなので何個書いてもOKだと思います。私はWebセーバーのFQDN(LAN内ローカルドメイン)も入れておきました。

P6) コマンドプロンプト(管理者)で、”C:\OpenSSL-Win32\bin”に入ります。

P7) 秘密鍵の生成(RSA2048bit) : openssl genrsa 2048 > server.key

P8) 署名リクエスト(CSR)の作成 : openssl req -new -key server.key -config openssl.cfg > server.csr
-configのスイッチで上記で編集したopenssl.cfgを読み込んでCSRを生成します。
*ここで、Common Nameは、公開するウェブサーバーのFQDNを入れておくのが無難な気がします。たぶん。

P9) Windows Server 2012 R2 CAのWeb CertSrvにアクセスしますが、いろいろな理由で付属のIE11でアクセスするのがよさそうです(Windows Server 2012 R2へリモートデスクトップで入っている状態で、その中のIE11)。LAN内の他のPCからのChromeアクセスなどでは上手くうごきませんでした。

IE11にて:https://YOUR_AD_SERVER/certsrv
*TLS(SSL)でアクセスするのでエラーが出ても続行する。TLSでアクセスしないと署名ができない。

P10) SAN属性を入力して署名をする。

*CSRのBASE64で貼り付けるのはいつも通り。
*追加属性の部分に、以下のフォーマットでSANの情報を追記する。おそらくP2), P3)の作業をしていないとこの属性を入力しても証明書にSANが追加されないと思われる。

追加属性フォーマット(SAN): san:dns=hoge.abc.yourdomain.com&dns=hoge2.abc.yourdomain.com&dns=abc.yourdomain.com

と好きなだけ追加する。

P11) 送信ボタンを押して(CAで署名)をして証明書をダウンロードし(例えばcertnew.cer)、ダブルクリックして証明書を表示する。

*赤枠にあるように「サブジェクト代替名」(=SAN)で、追加されているのが分かります。

P12) P11)の証明書(server.cer)と、P7)の秘密鍵(server.key)をLinuxサーバーにコピーし配置します。
CentOS7であれば、/etc/pki/tls/certs/以下でしょうかね。パーミッションは600。

P13) Apache2のssl.confを修正しデーモンを再起動

SSLCertificateFile /etc/pki/tls/certs/server.cer
SSLCertificateKeyFile /etc/pki/tls/certs/server.key

P14) LAN内のいろいろなホストから最新のChrome (ver58以降)でアクセス https://FQDN/
無事にエラーがなく表示できれば成功。

*Active Directoryを使っていれば当然だと思いますが、自己署名証明書をクリアするために、CAをグループポリシーで配布してある前提です。(certmgr – 信頼されたルート証明機関 > 証明書にWindows ServerのCA証明書が入っているのは前提です。

*参考:
R0) Chrome Deprecates Subject CN Matching – text/plain
R1) Configure Internal Windows CA to issue SAN certificates
R2) FAQ/subjectAltName (SAN)
R3) ssl – Generating a self-signed cert with openssl that works in Chrome 58 – Server Fault

*備忘録メモ:IISサーバー証明書インポート向け.pfx作成方法
M1) openssl pkcs12 -export -inkey server.key -in server.cer -out server.pfx

Share