应用程序架构设计指南2.0 第一部分 基本原则 第三章 架构设计指南[下] [翻译]

认证

设计一个好的身份验证策略对应用程序的安全性和可靠性是非常重要的。
没有设计和实现一个好的身份验证策略会让应用程序容易受到欺骗攻击,字典攻击,会话劫持和其他类型的攻击。

设计认证策略时,考虑以下原则:
 >标识信任边界,认证用户,和跨信任边界的调用。
  考虑调用可能需要从客户端认证,也可能从服务器端验证(相互认证).
 >如果用户程序有多个系统,并使用不同的用户库,考虑单点登录(SSO)策略。
 >不要以纯文本形式保存密码到数据库,相反,保存密码的哈希值。
 >强制使用强密码或者密码句子
 >密码不要以纯文本形式传输。

授权

设计一个良好的授权策略对于系统的安全性和可靠性是非常重要的。
没有设计并实现一个好的授权策略容易让系统受到信息暴露,数据篡改和特权提升攻击。

在设计授权策略时考虑以下原则:
 >标识信任边界,授权用户和跨边界的调用。
 >基于身份(identity),组(groups),或者角色(roles)应用授权给调用者来保护资源
 >为业务决策使用基于角色的授权。
 >为系统审计使用基于资源的授权。
 >当您需要支持基于混合信息,如身份(identity),角色,权限(permissions),权利(rights),
  以及其他因素的联合授权时,使用基于要求的授权。

缓存

缓存提高应用程序的性能和响应。然而,设计差劲的缓存策略可能会降低性能和响应。
您应该使用缓存优化参考数据查找,避免网络往返,并避免不必要的和重复处理。
要实现缓存,你必须决定何时加载缓存数据。
尝试异步地加载缓存或使用批处理,以避免客户端的延误。

在设计一个缓存策略时,考虑下列指导原则:
 >不缓存不稳定的数据。
 >考虑将随时可用的缓存数据加载到内存中的缓存。
  例如,缓存一个特定的对象,而不是缓存原始的数据库数据。
 >不要缓存敏感数据,除非你对这些数据进行了加密。
 >如果应用程序部署在Web环境,避免使用需要同步的本地缓存,
  而是考虑使用诸如事务性资源管理器如微软SQL Server或者支持分布式缓存的产品
 >不依赖于仍在缓存中的数据。它可能已被删除。

通信

通信涉及组件跨越不同的边界层之间的相互作用。
您选择的机制,取决于你的应用程序必须支持的部署场景。
当跨越物理边界,你应该使用基于消息的通信。
当跨越逻辑边界,你应该使用基于对象的通信。

设计沟通机制时,考虑以下原则:
 >为了减少不必要的来回,提高通信性能,设计厚实的接口。这样通信较少,但每个通信有更多信息。
 >跨AppDomain边界的通信使用非托管代码。
 >跨进程或物理边界考虑使用基于消息的通信。
 >如果您的消息不需要按严格的顺序接收,也没有相互依赖,考虑使用异步通信疏通处理或用户界面线程。
 >在系统或网络中断或故障的情况下,考虑使用微软消息队列(MSMQ)排队后递送信息。
  MSMQ的可以执行事务性的信息递送和支持可靠的一次性递送。

组合

组合是一个用来定义界面组件在用户界面中结构化展现的流程,为应用程序
提供一致的外观和感觉。用户界面设计的目标之一是提供
在一致的界面,以避免用户浏览应用程序时出现混淆。这可以通过使用模板实现,如ASP.NET的母版页,
或者,实现许多常见的设计模式中的一个。
 
设计组合时考虑以下原则:
 >避免使用动态的布局,因为他们可能难以载入和维护。
 >小心组件之间的依存关系。尽量避免可维护性问题时,可使用抽象模式。
 >考虑创建占位符(placeholders)模板。
 例如,使用模板视图模式撰写动态Web网页,以确保重用和一致性。
 >考虑用可重复使用的模块部件组成视图。
 例如,使用组合查看模式用模块化,原子的组件parts构建视图。

并发和事务

设计有关访问一个数据库的并发和事务时,
标识出要使用的并发模型和决定如何管理事务是很重要的。
对于数据库并发,最后一次更新有效的地方,可以选择乐观模式;只能更新最新版本的地方,使用悲观模式。
事务可以在数据库中执行,也可以在应用程序的业务层执行。
选择实现事务的地方依赖于您的交易需求。
当访问应用程序内部的静态数据,或使用线程执行异步操作时,也应该考虑并发。
静态数据不是线程安全的,这意味着在一个线程所做的更改会影响使用相同数据的其他线程。

设计并发和事务时,考虑以下原则:
 >如果您有关键业务操作,考虑在事务中包装(wrapping)他们。
 >访问单一的数据源时,使用基于连接的事务。
 >使用事务范围(System.Transaction)来管理跨越多个数据来源的事务。
 >实现补偿方法来恢复数据存储到以前的状态的地方,可以不使用事务。
 >避免长时间持有锁,例如,使用长时间运行原子事务时。
 >运用锁或使用线程同步后,对共享数据的更新应该是互斥的。
  这将阻止两个线程在同一时间更新共享数据的企图。
 >和静态或共享集合工作时,使用集合的同步功能。

配置管理

设计一个良好的配置管理机制对应用程序的安全性和灵活性是非常重要的。
如果不这样做可以使您的应用程序容易受到各种各样的攻击,并导致应用程序的管理开销。
 
设计配置管理时,考虑以下原则:
 >考虑使用最少权限的进程和服务帐户。
 >如果您的应用程序有多个层次(tiers),将配置项归类到逻辑节(sections)。
 >如果您的服务器应用程序运行在Web场,决定了配置的哪部分是共享的,哪部分是运行应用程序的机器上特有的。
  然后为每一节选择一个适当的配置存储。
 >加密敏感信息后,再储存在配置中。
 >限制访问您的配置信息。
 >为编辑配置信息提供一个独立的管理用户界面(UI)。

耦合和内聚

设计应用程序组件时,应该确保这些组件有高内聚,和跨层使用时的松耦合。
耦合是有关于依赖和功能。当一个组件依赖于另一个组件,和那个组件就是紧耦合。
功能可以解耦,不同的操作被分离,转化为唯一的组件。
内聚是指功能由一个组件提供。例如,一个组件,它提供了验证,日志和
数据访问操作, 这就是一个低内聚的组件。一个只提供日志操作的组件就是高内聚。

设计耦合和内聚时,考虑以下原则:
 >分割应用程序的功能到相应的逻辑层(layers)。
 >层与层之间设计为松耦合。考虑使用抽象实现层与接口组件,通用接口定义,或共同抽象之间的松耦合。
 共享抽象是指具体组件依赖抽象,不依赖其他具体组件(依赖反转原则)。
 >设计高内聚。组件应该只包含特定的和组件相关的功能。
 >知道松耦合接口的好处和开销。虽然松耦合需要更多的代码,好处包括缩短依赖链和简化构建过程。

数据访问

对于应用程序的可维护性和可扩展性,设计使用一个单独的数据访问层是重要的。
数据访问层应该负责管理和数据源的连接和执行对数据源的命令。
根据业务实体设计,数据访问层可能依赖于业务实体,但是,数据访问层绝不应该知道业务流程或工作流组件。

设计数据访问组件时,考虑以下原则:
 >避免应用程序模型直接耦合到数据库结构。相反,应该考虑在应用程序模型和数据库结构之间使用的抽象或映射层。
 >尽可能晚打开连接,尽早释放连接。
 >在数据库中,强制数据完整性,而不是通过数据层代码。
 >移动业务决策代码到业务层。
 >避免在应用程序的不同层直接访问数据库。相反,所有数据库交互应通过数据访问层处理。

异常管理

设计一个良好的异常管理策略对于应用程序的安全性和可靠性是非常重要的。
如果不这样做可以使应用程序容易受到拒绝服务(DoS)攻击,也可能泄露敏感和关键的信息。
提高认识和处理异常是一个昂贵的过程。设计时考虑性能问题也是重要的。
一个好的方法是设计一个集中的异常管理和日志记录机制,并考虑在异常管理系统内提供接入点,
以支持协助系统管理员的检测和集中监控。

在设计异常管理策略时,考虑以下原则:
 >不要捕获内部异常,除非你能处理,或需要增加更多的信息。
 >不要显示敏感信息到异常消息和日志文件。
 >设计一个适当的异常传播策略。
 >设计一个处理未处理异常的策略。
 >为严重错误和异常设计一个适当的记录和通知策略。 

分层

设计中层的使用允许您分离功能功能到不同的关注领域。
换句话说,层代表在设计中组件的逻辑分组。
您还应该定义层之间的沟通准则。例如,层A可访问层B,但层B不能访问层A。

设计层时应用考虑以下原则:
 >层应代表组件的逻辑分组。例如,用户界面,业务逻辑和数据访问组件各自使用单独的层。
 >同一层的组件应该是内聚的。换言之,业务层组件应该只提供应用程序业务逻辑相关的操作。
 >为每一层设计接口时,考虑物理边界。
  如果通讯跨越物理边界进行层的交互,使用基于消息操作。
  如果通信不跨越物理边界,使用基于对象操作。
 >考虑使用接口类型来定义每个层的接口。这将允许您创建该接口的不同实现改进可测性。
 >对于Web应用,在表示层和业务逻辑层之间实现基于消息的接口,即使层没有被物理边界分离。
  基于消息的接口更适合无状态的Web操作,提供了一个外观(Facade)给业务层,
  还允许从表现层物理解耦业务层,如果安全政策或响应安全审核需要。

 日志和检测

设计一个良好的日志和检测策略对于应用程序的安全性和可靠性是重要的。
如果不这样做会使应用程序容易受到抵赖威胁,用户否认他们的行动。
日志文件可能被需要用于法律诉讼以证明个人的不当行为。
您应该审计和记录跨越应用程序层的活动。
使用日志,可以检测到可疑的活动,可以提供严重攻击的早期指示。
一般来说,审计被认为是最有权威的,如果审计产生于存取资源的确切时间,通过同样的常规性的工作存取资源。
检测可以通过使用性能计数器和事件给予管理员关于应用程序的状态,性能信息,以及健康信息来实现。

设计日志和检测策略时,考虑以下指导原则:
 >集中日志和检测机制
 >设计应用程序内的检测来检查系统及关键业务的事件。
 >考虑怎样访问和传递跨应用程序层的审计和日志数据
 >创建安全日志文件管理政策。防止未经授权的日志文件查看。
 >不存储敏感信息在日志文件中。
 >考虑允许日志下沉(sinks),或跟踪监听器,可配置,使他们可以在运行时修改,以满足部署环境的要求

状态管理

状态管理涉及数据的持久性,它代表一个组件,操作或一个处理中的步骤的状态。状态数据可以使用不同的格式和存储持久化。
状态管理机制的设计能影响应用程序的性能。应该只持久化必需的数据,而且必须了解管理状态可用的选项。

设计状态管理机制时,考虑以下原则:
 >状态管理尽可能保持精简; 持久化维持状态所需的最少量的数据。
 >请确保状态数据是可序列化的,如果它需要跨进程和网络边界持久化或共享。
 >如果要构建一个Web应用程序,并且性能是你最关心的,使用一个进程内状态存储,如ASP.NET Session状态变量。
 >如果要构建一个Web应用程序,并希望状态持续到ASP.NET重新启动,使用ASP.NET Session状态服务。
 >如果应用程序部署在Web场(Web farm),避免使用本地状态管理存储,因为状态需要同步。
  例如,可以考虑使用远程Session状态服务或SQL Server状态存储。

结构

软件架构通常被定义为结构或应用程序的结构。
定义这些结构时,软件架构师的目标是通过分割项目到不同抽象层次的关注领域以最小化复杂性。
确定不同的关注领域,从审查抽象的更高层次开始。随着设计的进展,可以下潜到更深层次,扩展关注领域,直到确定所有的结构。

设计应用程序结构时,考虑以下原则:
 >确定已使用过的通用模式来描绘应用程序的结构,如客户端/服务器和N层。
 >了解应用程序部署环境的安全性要求。例如,许多安全政策需要从业务逻辑中物理分割(跨不同子网)出表示逻辑
 >考虑应用程序的可扩展性和可靠性要求。
 >考虑应用程序的部署场景。

用户体验

一个有效的用户体验设计对应用程序的成功可能是至关重要的。
如果导航是困难的,或者用户被定向到意外的页面,这种用户体验是消极的。

设计一个有效的用户体验时,考虑以下原则:
 >设计一致的导航体验。外观和感觉使用组合模式,以及诸如模型-视图-控制器(MVC)之类的控制模式,管理UI处理的控制器和被动视图。
 >设计接口,以便每个网页或部分聚集于特定的任务。
 >考虑分割有很多功能的大页面到小页面。
 >跨应用程序设计类似的组件要有一致的行为。例如,用来显示数据的网格应实现一致的分页和排序界面。
 >考虑使用已公开发表的UI指南。在许多情况下,一个组织都有已经公开发表的指南,应该遵守这些。

验证

设计一个有效的验证机制对应用程序的安全性和可靠性是非常重要的。
如果不这样做会使应用程序容易受到跨站点脚本,SQL注入,缓冲区溢出,恶意输入和其他类型攻击。
但是,没有标准的定义,可以区分恶意输入和有效输入。
此外,应用程序实际使用输入如何影响利用漏洞带来的风险。

设计验证机制时,考虑以下原则:
 >识别信任边界,并验证跨越信任边界的所有输入。
 >如果能够重用,集中验证方法。
 >限制,拒绝和净化用户输入。换言之,假设所有的用户输入都是恶意的。
 >验证输入数据的长度,格式,类型和范围。
 >安全检查不要只依赖客户端验证。
  应改为,使用客户端验证,给用户一些反馈和改进用户体验。
  由于攻击服务器时,客户端验证可以绕过,所以使用服务器端验证检查恶意输入。

工作流

应用程序必须执行一系列依赖信息内容的信息处理任务时,使用工作流组件。
工作流的价值在于影响信息处理的步骤,可以是从违反业务规则的数据检查到人员互动和输入的任何事情。
设计工作流组件时,考虑对工作流管理有效的选项是重要的。

设计工作流组件时,考虑以下原则:
 >确定管理要求。例如,如果商业用户需要管理工作流,需要提供一个商业用户可以理解的接口的解决方案。
 >确定如何处理异常。
 >使用服务接口与外部工作流供应者交互
 >如果支持,用设计器和元数据而不是代码来定义流程。
 >与人相关的工作流,要考虑用户的不确定性的天性。换句话说,你不能确定任务什么时候会完成,或者被正确完成。

 

posted @ 2009-10-24 13:12  Jack Tang  阅读(724)  评论(4编辑  收藏