昇格された特権/UACのプログラミング
必要以上の特権でアプリケーションを実行することは、最小特権の原則に反しており、潜在的なセキュリティの脆弱性がある可能性があります。これを防ぐために、Windows Vistaではユーザーアカウント制御(UAC)が導入され、現在のユーザーでも管理者としてサインインしている場合でも、特権が制限されたアプリケーションを(通常のユーザーとして)実行してオペレーティングシステムを保護します。ますます多くのXP/2Kユーザーが日常の使用に通常のユーザーアカウントを使用しています。UACを完全に理解するには、最初にUACDemystifiedをお読みください。
開発者が犯しがちな2つのよくある間違いがあります。
- エンドユーザーに管理者権限でアプリケーションを実行するように要求します。これは必要ではありませんが、ほとんどの場合、設計慣行が悪いためです。これらのアプリケーションは、エンドユーザーを怖がらせるか、セキュリティの脆弱性を潜在的に持っています。
- エンドユーザーにアプリケーションを昇格して実行するように要求しないでください。ただし、管理者権限が必要な操作を実行してみてください。これらのアプリケーションは、WindowsVistaまたはWindowsXP/2Kの通常のユーザーアカウントで動作します。
ダウンロード可能なサンプルコードは、昇格された特権/UACをプログラミングする方法を示しています。WPFとWindowsフォームの両方のサンプルアプリケーションが提供されています。次のシナリオでアプリケーションを実行して、違いを確認します。
- 通常のユーザー、Windows XP / Windows Vista:UACシールドアイコンが表示されます。「SavetoC:\」をクリックすると、「Run As」ダイアログが表示され、続行するには管理者パスワードの入力を求められます。
- 管理者、UACが無効になっているWindows XP / Windows Vista:UACシールドアイコンが非表示になっています。「C:\に保存」をクリックすると、ダイアログなしで完了します。
- 管理者、UACが有効になっているWindows Vista:UACシールドアイコンが表示されます。「C:\に保存」をクリックすると、続行するためのユーザーの許可を求めるダイアログが表示されます。
ダウンロードへのリンク
昇格された実行の呼び出し(最初に管理者をテスト):
private void SaveToRootFolder_Click(object sender, EventArgs e)
{
string fileName = @"C:\Test.txt";
if (App.IsAdmin)
DoSaveFile(textBox1.Text, textBox2.Text, fileName);
else
{
NameValueCollection parameters = new NameValueCollection();
parameters.Add("Text1", textBox1.Text);
parameters.Add("Text2", textBox2.Text);
parameters.Add("FileName", fileName);
string result = Program.ElevatedExecute(parameters);
if (!string.IsNullOrEmpty(result))
MessageBox.Show(result);
}
}
昇格された実行:
internal static string ElevatedExecute(NameValueCollection parameters)
{
string tempFile = Path.GetTempFileName();
File.WriteAllText(tempFile, ConstructQueryString(parameters));
try
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.UseShellExecute = true;
startInfo.WorkingDirectory = Environment.CurrentDirectory;
Uri uri = new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase);
startInfo.FileName = uri.LocalPath;
startInfo.Arguments = "\"" + tempFile + "\"";
startInfo.Verb = "runas";
Process p = Process.Start(startInfo);
p.WaitForExit();
return File.ReadAllText(tempFile);
}
catch (Win32Exception exception)
{
return exception.Message;
}
finally
{
File.Delete(tempFile);
}
}