常见的WEB安全措施

前两天面试一个remote职位,一个技术型的面试官,问的特别细致。
还记得其中一个是关于Github action的安全措施的。
这个考官也十分新奇,问的都很抽象。
他就问我在Github action中,都采用了什么样的安全措施。
我当时也是有点蒙,细节部分当时确实不是很清楚,直接说了句把重要信息都存在了Parameter Store来敷衍了过去。
所以也是为了给自己补补课,打算重新再认真总结下WEB系统常见的安全措施。

WEB安全,主要分为两个大块。一个是Application层面,一个是Network层面。Network的话,我自己也还不是特别熟悉,这次先主要总结下Application层面常见的应对措施。

  • 账号安全
  • CORS
  • Cross Site Scripting
  • SQL Injection
  • ClickJacking
  • POST、GET等Request Method的正确使用
  • 系统信息的加密,hash化
账号安全

主要包含账号注册,login,logout相关部分的处理。
账号注册方面:
・要注意不能使用太简单的密码,密码要经过加密处理
・为了避免恶意注册,要添加2段认证,比如通过email注册
login:
・页面里的auto complete最好关闭
・如果使用java的session管理功能的话,login前后的JSESSIONID务必要刷新
・为了防止暴力破解,要加入login尝试次数限制的机制
logout:
・logout不只是页面的迁移,之前的认证key也需要进行invalidate处理

CORS

使用API时有时会需要跨域,最好通过ALB的设置解决,商业环境ajax的跨域设置最好要关闭。Spring的话可以设置某些指定环境才打开CORS。

@Configuration
@Profile("default", "develop", "staging")
class CorsConfig {

    @Bean
    fun corsFilter(): FilterRegistrationBean<*> {

        val source = UrlBasedCorsConfigurationSource()
        val config = CorsConfiguration()
        config.allowCredentials = true
        config.addAllowedOrigin(CorsConfiguration.ALL)
        config.addAllowedHeader(CorsConfiguration.ALL)
        config.addAllowedMethod(CorsConfiguration.ALL)
        source.registerCorsConfiguration("/**", config)
        val bean = FilterRegistrationBean(CorsFilter(source))

        bean.setOrder(Ordered.HIGHEST_PRECEDENCE)
        return bean
    }
}

Cross Site Scripting

通过往数据库里写入script,然后在画面显示的时候去执行这些script。以用来窃取用户本地的信息。

SQL Injection

一般的系统安全的书中都会讲到,大概是10几年前比较常见的攻击方式吧。就是通过在query中注入一些查询语句,然后把查询内容显示到客户端。
CrossSiteScripting跟SQL Injection,早期web框架不成熟的时候应对起来比较麻烦,现在很多web框架都提供了相应的功能,相对来说对应也变得简单了。像在Spring中,就可以通过BeanValidation去限制< ‘等特殊字符的提交来解决问题。
下面这段示例代码就是对特殊字符做了限制,然后在DTO中通过使用 @field: IllegalWords 就可以(当前还需要@Valid使BeanValidation有效)了。

@Target(AnnotationTarget.FIELD, AnnotationTarget.VALUE_PARAMETER)
@Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
@ReportAsSingleViolation
@Constraint(validatedBy = [IllegalWordsValidator::class])
annotation class IllegalWords(
    val message: String = "validate.illegalwords",
    val groups: Array<KClass<out Any>> = [],
    val payload: Array<KClass<out Payload>> = []
)

class IllegalWordsValidator: ConstraintValidator<IllegalWords, String> {

    override fun initialize(constraintAnnotation: IllegalWords) {}

    override fun isValid(value: String?, context: ConstraintValidatorContext?): Boolean {
        return if (value == null || value.isEmpty()) {
            true
        } else {
            return !IllegalWordsValidator.PATTERN_ILLEGAL.matcher(value).find()
        }
    }

    companion object {
        private val PATTERN_ILLEGAL = Pattern.compile("[&<>\'\"]")
    }
}
ClickJacking
POST、GET等Request Method的正确使用

这部分在脆弱性测试里面经常出现。尤其是可以用来定位用户的信息,最好不要通过GET的参数去请求(比如userId、名字等个人信息等)。

系统信息的加密,hash化

这部分主要是内部管理相关。如果你的source code被某个开发小哥copy出去了,然后source里面包含着访问数据库或者服务器的key和serect,那么事情是不是就很糟糕了。所以为了避免这种情况,访问各种服务器的密码最好不要以明文的形式写在代码里面。以我当前碰到的情况的话,解决方案的大概有三种:
・以环境变量的形式写入到服务器中(比如使用提前在服务器中设置好)
・将密码存储到ParameterStore中
・将密码写在github repository的setting里

# github secrets使用示例
- name: Configure AWS Credentials
  uses: aws-actions/configure-aws-credentials@v1
  with:
    aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
    aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
    aws-region: ap-northeast-1

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

Close Bitnami banner
Bitnami