.NET安全系列之二:独立存储区相关知识
接上一篇文章,本文详细CAS中一个相对独立的问题 – 独立存储区,说到独立存储区,为什么说它与CAS有关呢,因为这涉及到CLR需要赋予程序的一种特殊权限即访问独立存储区的权限。
独立存储区的作用
在 一般的程序中给其访问硬盘的权限是该应用程序受到巨大信任的标志。使用移动代码的应用程序只有很少一部分能够被授予如此高的信任级别,所以大部分的移动代 码是无法访问本地磁盘,然而大多数应用程序都需要持久保存一些数据(如用户的个性化设置),即将数据保存在硬盘上。不授权此类程序访问磁盘会导致其无法正 常工作,授权其访问硬盘又会面临一个安全问题。独立存储区的出现正是解决这个问题。
针对移动代码可以授予其访问独立存储区的权限, 这样就能限制它们只访问在硬盘上的为其保留的某个文件夹的权限。而且可以限制应用程序可以使用的独立存储的大小。这样应用程序的移动代码对硬盘的访问就被 限制在它自己的独立存储文件夹(不同的应用程序会有不同的文件夹),这个文件夹也被称作沙箱。
上述所说的这个沙箱文件夹的在计算机 的位置及命名由多个因素决定:
- CLR
- 程序集的标识及包含该程序集的应用程序域标识
- 执行该应用程序的用户的标识
上述2、3两点中提到的标识被称作一个范围。每一种执行上下文(即一组不同的范围组合)对应一个独立存储文件夹,即一个应用 程序可以多个独立存储文件夹。应用程序每次在相同的上下文执行就会使用相同的文件夹。
System.IO.IsolatedStorage.IsolatedStorageFile类提供了一些静态方法来获得对应范围的文件夹。
GetUserStoreForAssembly()、GetMachineStoreForAssembly()、GetMachineStoreForDomain()及GetMachineStoreForApplication()。
最基本的访问独立存储文件夹的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | using System.IO; using System.IO.IsolatedStorage; class Program { static void Main() { //获取当前用户帐户及程序集的独立存储目录 IsolatedStorageFile isf =IsolatedStorageFile.GetUserStoreForAssembly(); IsolatedStorageFileStream isfs = new IsolatedStorageFileStream( "pref.txt" , FileMode.Create, isf); StreamWriter sw = new StreamWriter( isfs ); sw.WriteLine( "Put your preferences here..." ); sw.Close(); } } |
应用场合
独 立存储应用的场景很多,随着.NET2.0的广泛使用,ClickOnce的部署方式也日渐流行,部分传统的WinForm应用程序被以 ClickOnce方式部署,这样本是运行于本地计算机上的具有FullTrust权限的WinForm程序一下子变成了移动代码,从而权限收到限制,有 可能不能自由访问本地硬盘。这时候保存窗口大小、位置等信息的任务就要交由独立存储来完成,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using System.IO.IsolatedStorage; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.IO; namespace WindowsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load( object sender, EventArgs e) { try { IsolatedStorageFile isFile = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Assembly, null , null ); IsolatedStorageFileStream isFileStream = new IsolatedStorageFileStream( "Settings.isf" , FileMode.Open, isFile); //由二进制反序列化为类型 IFormatter formatter = new BinaryFormatter(); //获取窗体大小 this .Size = (Size)formatter.Deserialize(isFileStream); //获取窗体位置 this .Location = (Point)formatter.Deserialize(isFileStream); if ( null != isFileStream) isFileStream.Close(); if ( null != isFile) isFile.Close(); } catch (System.IO.FileNotFoundException ex) { MessageBox.Show(ex.ToString()); } } private void Form1_FormClosing( object sender, FormClosingEventArgs e) { IsolatedStorageFile isFile = IsolatedStorageFile.GetStore(IsolatedStorageScope.User | IsolatedStorageScope.Assembly, null , null ); //存储文件名为:Settings.isf IsolatedStorageFileStream isFileStream = new IsolatedStorageFileStream( "Settings.isf" , FileMode.OpenOrCreate, isFile); //序列话二进制文件 IFormatter formatter = new BinaryFormatter(); //存储窗体大小 formatter.Serialize(isFileStream, this .Size); //存储窗体位置 formatter.Serialize(isFileStream, this .Location); if ( null != isFileStream) isFileStream.Close(); if ( null != isFile) isFile.Close(); } } } |
代码出处
随着Silverlight2这种新型RIA应用程序的出现,独立存储又有了一个新的舞台,那就是用在Silverlight应用程序中,比较传统的ASP.NET Web应用程序中,信息被写入Cookies中,虽然Silverlight程序也可以操作Cookies,但是使用独立存储是一个更好的解决方案,独立存储不限制存储文件的类型,而且可用的空间较cookie更大(每个Silverlight应用),还可以在一定条件(用户允许)下扩充空间。Silverlight的独立存储是基于.NET Framework的独立存储建立的。
针对Silverlight独立存储的功能,在TerryLee的文章中摘录了部分方法(经简化),原文见此处:
增加独立存储目录:
1 2 3 4 5 6 7 8 9 10 | private void CreateDirectory() { using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) { if (!store.DirectoryExists(directoryName)) { store.CreateDirectory(directoryName); } } } |
写入文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | private void CreateFile() { using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) { String filePath = "a.txt" ; IsolatedStorageFileStream fileStream = store.CreateFile(filePath); using (StreamWriter sw = new StreamWriter(fileStream)) { sw.WriteLine( this .txtFileContent.Text); } fileStream.Close(); } } |
读取文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 | private void ReadFile() { using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) { String filePath = "a.txt" ; String Content; if (store.FileExists(filePath)) { StreamReader reader = new StreamReader(store.OpenFile(filePath, FileMode.Open, FileAccess.Read)); Content = reader.ReadToEnd(); } } } |
删除目录和文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | private void DeleteFile( string filePath) { using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) { if (filePath != "" ) { store.DeleteFile(filePath); } } } private void DeleteDirectory( string dirPath) { if (dir != "" ) { using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) { store.DeleteDirectory(dirPath); } } } |
获取目录与文件列表:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | private void GetFilesLst( string dirPath) { if (dirPath == "" ) { using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) { String[] files = store.GetFileNames(); } } else { using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) { String[] files = store.GetFileNames(dirPath + "/" ); } } } private void GetDirectoriesLst() { using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) { String[] directories = store.GetDirectoryNames( "*" ); } } |
增加用户存储空间,这个需要用户确认才能生效:
1 2 3 4 5 6 7 8 9 10 | using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication()) { long newQuetaSize = 5242880; long curAvail = store.AvailableFreeSpace; if (curAvail < newQuetaSize) { store.IncreaseQuotaTo(newQuetaSize); } } |
更多的还是参考TerryLee的文章啦!
参考:
-
《C#和.NET2.0实战》
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异