Web安全漏洞解決方案

2023-08-22 12:01:31

1.已解密的登入請求

 

推理: AppScan 識別了不是通過 SSL 傳送的登入請求。
測試請求和響應:

 1.1.1 產生的原因

 登入介面,前端傳入的密碼引數沒有經過md5的加密就直接傳給了後端

1.1.2 解決方法

前端程式碼傳參的時候做md5加密處理

 

2.對談標識未更新

推理: 測試結果似乎指示存在脆弱性,因為「原始請求」和「響應」中的對談標識相同。這些標誌應該已在響
應中更新。
測試請求和響應:

 

2.1.2 產生原因

對談標識未更新漏洞,在使用者進入登入頁面,但還未登入時,就已經產生了一個session,使用者輸入資訊,登入以後,session的id不會改變,也就是說沒有建立新session,原來的session也沒有被銷燬), 可能會竊取或操縱客戶對談和cookie,它們可能用於模仿合法使用者,從而使駭客能夠以該使用者身份檢視或變更使用者記錄以及執行事務。
 
2.1.3 解決方法
如果用的是shiro框架,使用 shiro自己提供的api方法 SecurityUtils.getSubject().logout(); 在登入驗證時生成新的session

 

 

3.「Content-Security-Policy」,「X-Content-Type-Options」,「X-Content-Type-Options」頭缺失或不安全

 

推理: AppScan 檢測到 Content-Security-Policy 響應頭缺失或具有不安全策略,這可能會更大程度地暴露於各種跨站點注入攻擊之下
 

 

推理: AppScan 檢測到「X-Content-Type-Options」響應頭缺失或具有不安全值,這可能會更大程度地暴露
於偷渡式下載攻擊之下
 

 

推理: AppScan 檢測到 X-XSS-Protection 響應頭缺失或具有不安全值,這可能會造成跨站點指令碼編制攻擊

 

3.1.1 產生原因

nginx.conf設定裡沒有新增對應的請求頭

 

3.1.2 解決方法

nginx.conf裡設定缺失的請求頭

 

4.垂直越權

4.1.1 漏洞分析

登入測試賬號test並分析下列JS程式碼:js/app.eb5ecba8.js
可獲取若干隱藏設定選單:

 

發現通過存取上述對應menuAction即可實現越權:
 
4.1.2.風險分析
攻擊者可基於低許可權賬戶獲取高許可權賬戶的模組許可權。
 
4.1.3.風險等級
 
4.1.4.安全建議
對相關menuAction對應的介面完善鑑權。
 
4.1.4.問題復現
1)瀏覽器開啟F12,找到vue.js中設定的一些專案介面的路由
2)登入低許可權test賬號,然後在位址列中直接存取vue.js中的某個路由地址,例如:http://221.***.**.50:58000/#/earlyReport 前提條件是該介面的是test使用者不具有存取許可權的一個模組中的介面
3)結果是在瀏覽器能夠直接存取介面所在的頁面,並能存取資料
 
4.1.5.什麼是垂直越權
一般越權漏洞容易出現在許可權頁面(需要登入的頁面)增、刪、改、查的的地方,當用戶對許可權頁面內的資訊進行這些操作時,後臺需要對對當前使用者的許可權進行校驗,看其是否具備操作的許可權,從而給出響應,而如果校驗的規則過於簡單則容易出現越權漏洞 ,簡單來說就是低許可權使用者能存取高許可權使用者,就是垂直越權
 
4.1.6.解決方法
採用AOP,切每個介面,對每個介面做許可權校驗;自定義一個註解,加在需要控制許可權的介面方法上,並且設定這個介面的許可權角色。然後通過AOP,切點就是這個自定義註解的方法,前置通知把方法攔截後,先拿到當前登入使用者的角色,再拿到自定義註解中該方法的許可權角色,根據這些判斷當前登入使用者有沒有許可權呼叫這個介面。如果有許可權請求正常繼續往下走,如果沒有許可權丟擲異常,程式碼如下:
 
自定義註解類:
 1 @Target(ElementType.METHOD)
 2 @Retention(RetentionPolicy.RUNTIME)
 3 public @interface SecurityAuth {
 4 
 5    /**
 6     * 擁有許可權的角色名
 7     * @retuen
 8     */
 9    String roleName();
10 }
AOP切點類:
 1 @Aspect
 2 @Component
 3 public class SecurityAspect {
 4 
 5     @Autowired
 6     private SysRoleUserService sysRoleUserService;
 7 
 8     /**
 9      * 自定義註解切點
10      */
11     @Pointcut("@annotation(com.broadu.modules.filter.SecurityAuth)")
12     public void annotationAspect(){}
13 
14     /**
15      * 前置通知
16      */
17     @Around("annotationAspect()")
18     public Object doBefore(ProceedingJoinPoint joinPoint) throws Throwable {
19         // 拿到響應
20         HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
21         // 拿到當前登入使用者
22         UserDetail user = SecurityUser.getUser();
23         if(null == user){
24             // 未登入
25             throw new RenException(ErrorCode.ACCOUNT_NOT_EXIST,"該使用者不存在");
26         }
27         // 從切面織入點處通過反射機制獲取織入點處的方法
28         MethodSignature signature = (MethodSignature) joinPoint.getSignature();
29         // 獲取切入點所在的方法
30         Method method = signature.getMethod();
31         // 獲取註解
32         SecurityAuth auth = method.getAnnotation(SecurityAuth.class);
33         // 獲取該方法使用的角色
34         String roleNames = auth.roleName();
35         // 獲取該使用者的角色列表
36         if(ObjectUtil.notEqual(user.getSuperAdmin(),1)){
37             List<String> roleList = sysRoleUserService.getRoleNameList(user.getId());
38             List<String> list = new ArrayList<>();
39             if(null != roleList && roleList.size() > 0){
40                 String[] roleName = roleNames.split(",");
41                 for (String str : roleName) {
42                     for (String s : roleList){
43                         if(ObjectUtil.equal(str,s)){
44                             list.add(s);
45                             break;
46                         }
47                     }
48                 }
49                 if(list.size() == 0){
50                     // 沒有許可權
51                     throw new RenException(ErrorCode.ACCOUNT_NOT_PERMISSION,"該使用者無許可權存取");
52                 }
53             }
54         }
55         // 有許可權
56         return joinPoint.proceed();
57     }
58 
59 }
Controller類:
 1 @RestController
 2 @Slf4j
 3 @RequestMapping("/ftpConfiguration")
 4 public class FtpConfigurationController {
 5 
 6     @Autowired
 7     FtpConfigurationService ftpConfigurationService;
 8 
 9     @Autowired
10     FactorService factorService;
11 
12     @SecurityAuth(roleName = "使用者角色")
13     @GetMapping("/page")
14     @ApiOperation("統計報表")
15     public Result<PageData<FtpConfigurationDto>> page(@ApiIgnore @RequestParam Map<String, Object> params) {
16         PageData<FtpConfigurationDto> page = ftpConfigurationService.page(params);
17         List<FtpConfigurationDto> list = page.getList();
18         // 使用者密碼md5加密
19         list.forEach(item ->{
20             try {
21                 item.setPassword(DigestUtils.md5Hex(item.getPassword()));
22             } catch (Exception e) {
23                 log.info("加密異常資訊:{}"+e.getMessage());
24             }
25         });
26         page.setList(list);
27         return new Result<PageData<FtpConfigurationDto>>().ok(page);
28     }
 
前端也對程式碼做了相關的許可權校驗

 

靜態路由繫結按鈕跳轉:

 

4.1.7.驗證是否修復成功
先用不是使用者角色的使用者登入系統後,然後直接在瀏覽器地址輸入「分頁查詢使用者列表」的url,檢視頁面上是否有資料返回。如果有,則說明漏洞沒修復成功;如果沒有,則修復成功。