代码审计——基础(JAVAEE)
JAVAEE
常见框架
Struct2(控制层)
- MVC设计模式实现
- 拦截器
- 可变和可重用的标签a
Hibernate(持久层(与数据库交互)(不用再写简单的sql语句,但是需要一些列复杂的配置文件))(全ORM模型)
- ORM,简化数据库操作
- DAO层
Spring(大管家)
- 依赖注入容器/AOP实现
- 声明式事务
- 简化JAVA EE应用
- 粘合剂,将大家组装在一起
Spring MVC(控制层)
- 结构最清晰的MVC Model2实现
- 高度可配置,支持多种视图技术
- 定制化开发
Mybatis(半ORM)(目前的主流框架)
- 半自动化的ORM实现
- DAO层
- 动态SQL
- 小巧灵活、简单易学
Spring
Spring框架负责管理各种对象(提供一个平台)
- IOC容器管理各层的组件
- 使用AOP配置声明式事务
- 整合其它框架
AOP
Aspect Oriented Program,面向(方面)切面的编程,Filter(过滤器)也是一种AOP。AOP是一种新的方法论,是对传统OOP(Object-Oriented Programming,面向对象编程)的补充,AOP的主要编程对象是切面(aspect),而切面模块化横切关注点。
不同程序中的相同方法抽取出来,使用Springboot进行统一管理,面向切面编程
IOC
Invert Of Control,控制反转,也称为DI(依赖注入)其思想是反转资源获取方向。传统资源查找方式要求组件向容器发起请求查找资源,作为回应,容器适时的返回资源。而应用了IOC之后,则是容器主动将资源推送给它所管理的组件,组件所要做的仅是选择一种合适的方式来接受资源。这种行为被称为查找的被动形式
spring配置bean
Bean配置方式:通过全类名(反射)、通过工厂方法(静态工厂方法&实例工厂方法)、FactoryBean
声明周期管理
- 通过构造器或工厂方法创建Bean实例
- 为Bean的属性设置值和对其它Bean的引用
- 将Bean实例传递给Bean前置处理器的postProcessBeforeInitialization方法
- 调用Bean的初始化方法(init-method)
- 将Bean实例传递给Bean后置处理器的postProcessAfterInitialization方法
- Bean方法可以使用
- 当容器关闭时,调用Bean方法的教会方法(destory-method)
SSH工作流程
- Struct2负责显示页面和接受请求
- Spring的IOC容器管理各个组件:整合Struct2,Hibernate和其它组件,AOP完成声明式事务
- Hibernate提供DAO操作
Shiro
传统意义上如何实现用户接口的鉴权?
5张表
权限表:将应用系统所有的URL、按钮、菜单等类型的权限存储到数据表
用户表:存储系统所有的用户
角色表:将系统总结出来几种角色
用户-角色表:将用户和角色建立连接
角色-权限表:将角色和权限建立连接。
最后实现的效果:
(1)等用户登录系统之后,系统根据用户名,密码以及随机的字符串生成了一个token或cookies,这就是唯一标识
(2)通过用户名查询到用户的id,通过用户的id在用户-角色表中查
到了这个用户被赋予了那些角色
(3)获取到这个用户的角色到角色-权限表中查询到了这些角色拥有了哪些权限
(4)系统获取到了授权范围的权限和当前用户访问的权限进行比对,如果在范围内放行如果不在范围内终止访问。
只有通过这种方式去鉴权,才能够实现用户和权限的动态绑定。
如何实现数据的鉴权?
必须通过sql语句的条件控制实现,数据一定被分为公开数据,私有数据。
私有数据:当用户访问私有数据的时候,需要获取到这个用户的ID,去判断这个ID是不是这条数据所属用户表或者是高角色管理员
优点
- 简单的身份认证,支持多种数据源
- 对角色的简单授权,支持细粒度的授权(方法级)
- 支持一级缓存,以提升应用程序性能
- 内置的基于POJO企业会话管理,适用于Web以及非Web的环境
- 非常简单的加密API
- 不跟任何框架或容器捆绑,可独立运行
核心组件
- Subject:正与系统进行交互的人,或某一个第三方服务。所有Subject实例都被绑定到(且这是必须的)一个SecurityManager上
- SecurityManager:Shiro架构的心脏,用来协调内部安全组件,管理内部组件实例,并通过它来提供安全管理的各种服务。当shiro与一个Subject进行交互时,实质上是幕后的SecurityManager处理所有繁重的subject安全操作
- Realms:本质上是一个特定安全的DAO。当配置shiro时,必须指定至少一个Realm用来进行身份验证或授权
- Shiro提供了多种可用的Realms来获取安全相关的数据。如关系数据库(JDBC),INI及属性文件等。可以定义自己Realm实现来代表自定义的数据源
认证过程
- 应用程序代码调用Subject.login方法,传递创建好的包含终端用户的Principals(身份)和Credentials(凭证)的AuthenticationToken实例
- Subject实例:通常为DelegatungSubject(或子类)委托应用程序的SecurityManager通过调用securityManager.login(token)开始真正的验证
- SubjectManager接受token,调用内部的Authenticator实例调用authenticator.authenticate(token).Authenticator通常是一个ModularRealmAuthenticator实例,支持在身份验证中协调多一个Realm实例
- 如果应用程序中配置了一个以上的Realm,ModularRealmAuthenticator实例将利用配置好的AuthenticationStrategy来启动Multi-Realm认证尝试.在Realms被身份验证调用之前,期间和以后AuthenticationStrategy被调用使其能够对每个Realm的结果作出反应
- 每个配置的Realm用来帮助看它是否支持提交的AuthenticationToken.如果支持,那么支持Realm的getAuthenticationlnfo方法将会伴随着提交的token被调用getAuthenticationlnfo方法有效地代表一个特定Realm的单一的身份验证尝试。
授权过程
- 应用程序或框架代码调用任何Subject的hasRole,checkRole,isPermitted,或者checkPermission方法的变体,传递任何所需的权限
- Subject的实例一通常是DelegatingSubject(或子类),调用securityManager的对应的方法
- SecurityManager调用org.apache.shiro.authz.Authorizer接口的对应方法
- 默认情况下,authorizer实例是一个ModularRealmAuthorizer实例,它支持协调任何授权操作过程中的一个或多个Realm实例
- 每个配置好的Realm被检查是否实现了相同的Authorizer接口.如果是,Realm各自的hasRolecheckRole,isPermitted或checkPermission方法将被调用
自实现授权
实际开发中,通常提供org.apache.shiro.realm.AuthorizingRealm的实现类,并提供doGetAuthorizationInfo(PrincipalCollection principals)方法的具体实现
Spring中配置shiro
- 在web.xml中配置Shiro的Filter
- 在Spring的配置文件中配置Shiro
配置自定义Realm:实现自定义认证和授权
配置Shiro实体类使用的缓存策略
配置SecurityManager
配置保证Shiro内部Bean声明周期都得到执行的Lifecycle Bean后置处理器
配置AOP式方法级权限检查
配置Shiro Filter
Spring MVC
概述
模型-视图-控制器(MVC)是一个众所周知的以设计界面应用程序为基础的设计模式。它主要通过分离模型、视图及控制器在应用程序中的角色将业务逻辑从界面中解耦。通常,模型负责封装应用程序数据在视图层展示。视图仅仅只是展示这些数据,不包含任何业务逻辑。控制器负责接收来自用户的请求,并调用后台服务(manager或dao)来处理业务逻辑。处理后,后台业务层可能会返回一些数据在视图层展示。控制器收集这些数据及准备模型在视图层展示。MVC模式的核心思想是将业务逻辑从页面中分离出来,允许它们单独改变而不会影响。
框架优势
- 清晰的角色划分:前端控制器(DispatcherServlet)请求到处理映射(HandlerMapping)处理适配器(HandlerAdapter)视图解析器(ViewResolver)处理器或页面控制器(Controller)验证器(Validator)命令对象(Command 请求参数绑定到的对象就叫命令对象)表单对象(Form Object 提供给表单展示和提交到的对象叫表单对象)
- 分工明确,且扩展点相当灵活,可以很容易扩展,虽然几乎不需要
- 由于命令对象就是一个POJO,无需继承框架特定API,可以使用命令对象直接作为业务对象
- 和Spring其它框架无缝集成,是其它Web框架所不具备的
- 可适配,通过HandlerAdapter可以支持任意类作为处理器
- 可定制性,HandlerMapping、ViewResolve等能够非常简单的定制
- 功能强大的数据验证、格式化、绑定机制
- 利用Spring提供的Mock对象能够非常简单的进行Web层单元测试
- 本地化、主题的解析的支持,使我们更容易进行国际化和主题的切换
- 强大的JSP标签库,使JSP编写更容易
- 还有比如RESTful风格的支持、简单的文件上传、约定大于配置的契约式编程支持、基于注解的零配置支持等等
原理流程
具体步骤如下:
- 首先用户发送请求——>前端控制器,前端控制器根据请求信息(URL)来决定选择哪一个页面控制器进行处理并把请求委托给它,即以前的控制器的控制逻辑部分[图1,2]
- 页面控制器接收到请求后,进行功能处理,首先需要收集和绑定请求参数到一个对象,这个对象在Spring Web MVC中叫命令对象,并进行验证,然后将命令对象委托给业务对象进行处理;处理完毕后返回一个ModelAndView(模型数据和逻辑视图名)[图3,4,5]
- 前端控制器收回控制权,然后根据返回的逻辑视图名,选择相应的视图渲染,并把模型数据传入以便视图渲染[图6,7]
- 前端控制器再次收回控制权,将响应返回给用户[图8]
组件总结
- DispatcherServlet前端控制器(不需要程序员写),负责框架调度,相当于中央处理器,基本Controller控制器功能:接收用户requesti请求和给用户response响应。
- HandlerMapping(处理器映射器)(不需要程序员写)负责根据action的连接找到Handler处理器(理解成写的action)。
- HandlerAdapter(处理器适配器)(不需要程序员写)负责去执行Handler。
- Handler(处理器)需要程序员写理解成struts里边的action,需要程序员写action类,这个action类符合适配器的执行规则。
- ViewResolver(视图解析器)(不需要程序员写)负责将模型数据填充到View。
- View视图,需要程序员写jsp页面。
操作步骤
基于Spring MVC框架进行开发,需要依赖Spring jar包
配置文件及编写代码
使用@RequestMapping
映射请求
Spring MVC使用
@RequestMapping
注解为控制器指定可以处理哪些URL请求在控制器的类定义及方法定义处都可标注@RequestMapping
类定义处:提供初步的请求映射信息。相对于WEB应用的根目录
方法处:提供进一步的细分映射信息。相对于类定义处的URL若类定义处未标注
@RequestMapping
,则方法处标记的URL相对于WEB应用的根目录
DispatcherServlet截获请求后,就通过控制器上@RequestMapping
提供的映射信息确定请求所对应的处理方法
当访问index.jsp时,页面上会展示一个超链接,点击超链后,url中的地址就会发生跳转,由http://localhost:8080/springTest/index.jsp跳转到http://localhost:8080/springTest/helloworld,而这个url请求就会进入HelloWorld中的hello方法,因为其与该方法上的“/helloworld”匹配。
当springmvc.xml中声明了prefix和suffix,而夹在这两者之间的就是这里返回的字符串,所以执行完这个方法后,我们可以得到这样的请求资源路径“WEB-INF/views/success.jsp”
问题:SpringMVC如何访问静态资源?
- 关于使用Spring MVC处理静态资源,比如html(发现之前的springmvc.xml中定义为jsp结尾就可以成功跳转,但是如果改为html并在web-inf下新建html文件后,并将suffix这里的.jsp改为.html,无法跳转到想要的html画面,并给出404错误,同时console给出错误信息:No mapping found for HTTP request with URL [/springTest/WEB-INF/views/result.html] in DispatcherServlet)
- 最后发现是需要让spring明确要处理静态资源,原来的web.xml只有其匹配的都是controller中类以@RequestMapping("/springmvc/helloworld")这样的注解配置的请求而对于类似html/css/jpg等资源的访问就会得不到,所以需要在web.xml中加入以下类型的支持,这样就可以保证spring能够拦截并处理静态资源。
Struct2
Struts2是一个用来开发MVC应用程序的框架.它提供了Wb应用程序开发过程中的一些常见问题的解决方案
- 对来自用户的输入数据进行合法性验证
- 统一的布局
- 可扩展性
- 国际化和本地化
- 支持Ajax
- 表单的重复提交
- 文件的上传下载
Action类
- action:应用程序可以完成的每一个操作.例如:显示一个登陆表单:把产品信息保存起来
- Action类:普通的Java类,可以有属性和方法,同时必须遵守下面这些规则:
属性的名字必须遵守与JavaBeans属性名相同的命名规则.属性的类型可以是任意类型.从字符串到非字符串(基本数据库类型)之间的数据转换可以自动发生
必须有一个不带参的构造器
至少有一个供struts在执行这个action时调用的方法
同一个Action类可以包含多个action方法
Struts.2会为每一个HTTP请求创建一个新的Action实例
访问WEB资源
与Servlet耦合的访问方式
- 直接访问Servlet API将使Action与Servlet环境耦合在一起,测试时需要有Servlet容器,不便于对Action的单元测试
- 直接获取HttpServletRequest对象
ServletActionContext.getRequest() - 直接获取HttpSession对象
ServletActionContext.getRequest().getSession() - 直接获取ServletContext对象
ServletActionContext.getServletContext() - 通过实现ServletRequestAware,ServletContextAware等接口的方式
result
- 每个action方法都将返回一个String类型的值,Struts将根据这个值来决定响应什么结果
- 每个action声明都必须包含有数量足够多的result元素,每个result元素分别对应着action方法的一个返回值
- result元素可以有下面两个属性
name:结果的名字,必须与Action方法的返回值相匹配,默认值为success
type:响应结果的类型.默认值为dispatcher
通配符映射
- 一个Wb应用可能有成百上干个action声明.可以利用struts提供的通配符映射机制把多个彼此相似的映射关系简化为一个映射关系
- 通配符映射规则
若找到多个匹配,没有通配符的那个将胜出
若指定的动作不存在,Struts将会尝试把这个UR!与任何一个包含着通配符*的动作名及进行匹配
被通配符匹配到的U1字符串的子串可以用{1,{2)来引用.1}匹配第一个子串,{2}匹配第二个子
串…
{0}匹配整个URL
若Struts找到的带有通配符的匹配不止一个,则按先后顺序进行匹配
可以匹配零个或多个字符,但不包括/字符.如果想把/字符包括在内,需要使用**.如果需要对某个字符进行转义,需要使用.
Structs对文件上传的支持
-
在Struts应用程序里,FileUpload拦截器和Jakarta Commons FileUpload组件可以完成文件的上传
-
步骤:
-
在Jsp页面的文件上传表单里使用fle标签.如果需要一次上传多个文件,就必须使用多个file标签,但它们的名字必须是相同的
-
在Action中新添加3个和文件上传相关的属性.这3个属性的名字必须是以下格式
[File Name]File-被上传的文件。例如:data
[File Name]ContentType:String-上传文件的文件类型。例如:dataContentType
[File Name]FileName:String-上传文件的文件名。例如:dataFileName
-
如果上上传多个文件,可以使用List
-
配置FileUpload拦截器
- (1)FileUpload拦截器有3个属性可以设置
maximumSize:上传单个文件的最大长度(以字节为单位),默认值为2MB
allowedTypes:允许上传文件的类型,各类型之间以逗号分隔
allowedExtensions:允许上传文件扩展名,各扩展名之间以逗号分隔
可以在struts.xml文件中覆盖这3个属性 - (2)Commons FileUpload组件默认按受上传文件总的最大值为2M,可以通过在struts配置文件中配置常量的方式修改
- (3)与文件上传有关的出错消息在struts-messages.properties文件里预定义.可以在文件上传Action相对应的资源文件中重新定义错误消息
- (1)FileUpload拦截器有3个属性可以设置
-
Stream结果类型
- Struts专门为文件下载提供了一种Stream结果类型 在使用一个Stream结果时,不必准备一个JSP页面
- Stream结果类型可以设置如下参数:
contentType:被下载的文件的MlME类型。默认值为text/plain
contentLength:被下载的文件的大小,以字节为单位
contentDisposition:可以设置下载文件名的ContentDispositon响应头,默认值为inline,通常设置为如下格式:attachment;filename="document.pdf
inputName:Action中提供的文件的输入流。默认值为inputStream
bufferSize:文件下载时缓冲区的大小。默认值为1024
allowCaching:文件下载时是否允许使用缓存。默认值为true
contentCharSet:文件下载时的字符编码。
Stream结果类型的参数可以在Action以属性的方式覆盖
Struct2解决表单重复提交
Struct2拦截器
- 拦截器(Interceptor)是Struts2的核心组成部分。
- Struts2很多功能都是构建在拦截器基础之上的,例如文件的上传和下载、国际化、数据类型转换和数据校验等等。
- Struts.2拦截器在访问某个Action方法之前或之后实施拦截。
- Struts.2拦截器是可插拔的,拦截器是AOP(面向切面编程)的一种实现。
- 拦截器栈(Interceptor Stack):将拦截器按一定的顺序联结成一条链.在访问被拦截的方法时,Struts.2拦截器链中的拦截器就会按其之前定义的顺序被依次调用。
整合Spring
- Struts2通过插件实现和Spring的整合
- Struts2提供了两种和Spring整合基本的策略:
- 将Action实例交给Spring容器来负责生成.管理,通过这种方式,可以充分利用Spring容器的IOC特性,提供最好的解耦
- 利用Spring插件的自动装配功能,当Spring插件创建Action实例后,立即将Spring容器中对应的业务逻辑组件注入Action实例
SpringMVC比较Structs2
- Spring MVC的入口是Servlet,而Struts2是Filter
- Spring MVC会稍微比Struts2快些.Spring MVC是基于方法设计,而Sturts2是基于类,每次发一次请求都会实例一个Action.Spring MVC使用更加简洁,开发效率Spring MVC确实比struts2高:支持JSR303,处理ajax的请求更方便
- Struts2的OGNL表达式使页面的开发效率相比Spring MVC更高些