为您推荐:
精华内容
最热下载
问答
  • 5星
    18KB m0_44995828 2020-12-16 21:46:42
  • 5星
    838KB qq_43729828 2021-08-09 15:56:48
  • 此文为:轻松入门cmake系列教程 实践 1、 cmake debug和release设置 # default is "Debug" #set(CMAKE_BUILD_TYPE "Release") ...3、根据cmake的debug和release设置编译选项 IF("${CMAKE_BUILD_TYPE}" .

    此文为:轻松入门cmake系列教程

    实践

    1、 cmake debug和release设置

    # default is "Debug"
    #set(CMAKE_BUILD_TYPE "Release")
    
    
    if (!CMAKE_BUILD_TYPE STREQUAL "RELEASE")
    		add_definitions("-g")
    endif()
    

    2、启用Makefile版本中的详细输出。

    # set this to see the compilation commands
    # set(CMAKE_VERBOSE_MAKEFILE 1)
    

    3、根据cmake的debug和release设置编译选项

    IF("${CMAKE_BUILD_TYPE}" MATCHES "Debug")
        message(STATUS "building for: debugging")
    
        ## unfortunately these produce errors
        #include(CheckCXXCompilerFlag)
        #CHECK_CXX_COMPILER_FLAG("-Wformat-signedness" CXX_FORMAT_SIGNEDNESS)
        #CHECK_CXX_COMPILER_FLAG("-Werror=format-security" CXX_FORMAT_SECURITY)
        #CHECK_CXX_COMPILER_FLAG("-fstack-protector-all" CXX_STACK_PROTECTOR)
        set(CXX_FORMAT_SIGNEDNESS "-Wformat-signedness")
        set(CXX_FORMAT_SECURITY "-Werror=format-security")
        set(CXX_STACK_PROTECTOR "-fstack-protector-all")
        set(CXX_FLAGS_DEBUG "-O0")
        set(CMAKE_C_STANDARD 99)
        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O1 -ggdb -Wall -Wextra -DNETDATA_INTERNAL_CHECKS=1 -DNETDATA_VERIFY_LOCKS=1 ${CXX_FORMAT_SIGNEDNESS} ${CXX_FORMAT_SECURITY} ${CXX_STACK_PROTECTOR} ${CXX_FLAGS_DEBUG}")
    ELSE()
        message(STATUS "building for: release")
        cmake_policy(SET CMP0069 "NEW")
        include(CheckIPOSupported)
        check_ipo_supported(RESULT ipo_supported OUTPUT error)
        IF(${ipo_supported})
            message(STATUS "link time optimization: supported")
            set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
        ELSE()
            message(STATUS "link time optimization: not supported")
        ENDIF()
    ENDIF()
    
    

    设置CMAKE_CXX_FLAGS

    # Use C++11.
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")  #禁用运行时类型信息
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")  # 禁用异常机制
    

    理论

    GCC编译选项

    • -E:只进行预处理,不编译
    • -S:只编译,不汇编
    • -c:只编译、汇编,不链接
    • -g:包含调试信息
    • -I:指定include包含文件的搜索目录
    • -o:输出成指定文件名

    常用选项

    优化选项

    • -O0:关闭所有优化选项
    • -O1:第一级别优化,使用此选项可使可执行文件更小、运行更快,并不会增加太多编译时间,可以简写为-O
    • -O2:第二级别优化,采用了几乎所有的优化技术,使用此选项会延长编译时间
    • -O3:第三级别优化,在-O2的基础上增加了产生inline函数、使用寄存器等优化技术
    • -Os:此选项类似于-O2,作用是优化所占用的空间,但不会进行性能优化,常用于生成最终版本

    高级选项

    • -ggdb:在可执行文件中包含可供 GDB使用的调试信息
    • -v:详细输出编译过程中所采用的每一个选项
    • -C:预处理时保留注释信息
    • -fverbose-asm:在编译成汇编语言时,把C变量的名称作为汇编语言中的注释
    • -save-temps::自动输出预处理文件、汇编文件、对象文件,编译正常进行
    • -fsyntax-only::只测试源文件语法是否正确,不会进行任何编译操作
    • -ffreestanding:编译成独立程序,而非宿主程序

    出错提示

    当GCC在编译过程中检查出错误的话,它就会中止编译;但检测到警告时却能继续编译生成可执行程序,因为警告只是针对程序结构的诊断信息,它不能说明程序一定有错误,而是存在风险,或者可能存在错误。虽然GCC提供了非常丰富的警告,但前提是你已经启用了它们,否则它不会报告这些检测到的警告。

    • -Wall:开启大部分警告提示
    • -Wextra:对所有合法但值得怀疑的表达式发出警告
    • -w:忽略所有警告
    • -Werror:不区分警告和错误,遇到任何警告都停止编译
    • -Wshadow:一旦某个局部变量屏蔽了另一个局部变量,编译器就发出警告.(此警告未包含在-Wall选项中,需单独开启)
    • -Wlong-long
      • 如果使用了long long 类型就发出警告.
      • 该警告是缺省项.
      • 使用-Wno-long-long选项能够防止这个警告.
      • -Wlong-long-Wno-long-long仅在 -pedantic之下才起作用.
    • -Waggregate-return
      • 如果定义或调用了返回结构或联合的函数,编译器就发出警告
      • (从语言角度你可以返回一个数组,然而同样会 导致警告.)
    • -Wstrict-prototypes
      • 如果函数的声明或定义没有指出参数类型,编译器就发出警告.
      • (如果函数的前向引用说明指出了参数类型,则允许后面 使用旧式风格的函数定义,而不会产生警告.)
    • -Wmissing-prototypes
      • 如果没有预先声明函数原形就定义了全局函数,编译器就发出警告
      • 即使函数定义自身提供了函数原形也会产生这个警告.
      • 他的目的是检查没有在头文件中声明的全局函数.

    使用示例:-Wall选项

    在众多的警告选项之中,最常用的就是-Wall选项。该选项能发现程序中一系列的常见错误警告,该选项用法举例如下:

    • 命令行:
    $ gcc -Wall test.c -o test
    
    • cmakelist.txt:
    add_definitions(
    		"-W"
    		"-Wall"
    		"-Werror"
    		"-Wshadow"
    )
    

    该选项相当于同时使用了下列所有的选项:

    • unused-function:遇到仅声明过但尚未定义的静态函数时发出警告。
    • unused-label:遇到声明过但不使用的标号的警告。
    • unused-parameter:从未用过的函数参数的警告。
    • unused-variable:在本地声明但从未用过的变量的警告。
    • unused-value:仅计算但从未用过的值得警告。
    • Format:检查对printf和scanf等函数的调用,确认各个参数类型和格式串中的一致。
    • implicit-int:警告没有规定类型的声明。
    • implicit-function-:在函数在未经声明就使用时给予警告。
    • char-subscripts:警告把char类型作为数组下标。这是常见错误,程序员经常忘记在某些机器上char有符号。
    • missing-braces:聚合初始化两边缺少大括号。
    • Parentheses:在某些情况下如果忽略了括号,编译器就发出警告。
    • return-type:如果函数定义了返回类型,而默认类型是int型,编译器就发出警告。同时警告那些不带返回值的 return语句,如果他们所属的函数并非void类型。
    • sequence-point:出现可疑的代码元素时,发出报警。
    • Switch:如果某条switch语句的参数属于枚举类型,但是没有对应的case语句使用枚举元素,编译器就发出警告(在switch语句中使用default分支能够防止这个警告)。超出枚举范围的case语句同样会导致这个警告。
    • strict-aliasing:对变量别名进行最严格的检查。
    • unknown-pragmas:使用了不允许的#pragma。
    • Uninitialized:在初始化之前就使用自动变量。

    需要注意的是,各警告选项既然能使之生效,当然也能使之关闭。比如假设我们想要使用-Wall来启用个选项,同时又要关闭unused警告,利益通过下面的命令来达到目的:

     gcc -Wall -Wno-unused test.c -o test
    

    使用示例:-Wpointer-arith

    • 任何语句如果依赖于函数类型的大小(size)或者void类型的大小,编译器就发出警告.
    • GNU C为了 便于计算void *指针和函数指针,就把这些类型的大小定义为1.
    • 在C++中,当算术运算涉及"NULL"时也要发出警告.
    #include <stdio.h>
    int main() {
        void *test = NULL;
        int value_int[] = {12, 34, 56, 67, 27};
        char value_char[] = {'H', 'e', 'I', 'I', 'O'};
    
        test = (void *) value_char;
        printf("%c\n", *((char*)(test + 1)));
        return 0;
    }
    

    在这里插入图片描述

    -Waggregate-return

    • -Waggregate-return: 当返回结构、联合或数组时给出警告

    引发警告的小例子:

    class foo{};
    foo f(void){return foo{};}
    int main(){}
    $ g ++ -std = c ++ 0x -Waggregate-return -o main main.cpp
    main.cpp:在函数'foo f()':
    main.cpp:2:5:warning:函数返回一个聚合[-Waggregate-返回]
    

    另一个不引发警告的小例子:

    #include <string>
    std::string f(void){return "test";}
    int main(){}
    

    使用-Waggregate-return可以获得什么好处?
    为什么有人想要对此发出警告?
    另外,std :: string不是一个类吗? - 为什么我不警告第二个例子中的’返回聚合’?

    回答:
    主要有两种可能的解释:

    • 1)警告用户返回聚合对象使他意识到如果返回聚合对象(在堆栈上分配),堆栈可能会溢出.
    • 2)显然,一些旧的C编译器不支持返回aggrregates(你必须返回一个指针).

    讨论请参见这里

    -Wmissing-prototypes

    这个选项仅适用于C编译,如果是C++,会警告:

    在这里插入图片描述

    讨论请参见这里

    语言标准

    • -ansi:ANSI标准
    • -std=c99:C99标准
    • -std=gnu89:ISO/IEC 9899:1990 以及GNU扩充
    • -std=gnu99:ISO/IEC 9899:1999 以及GNU扩充
    • -trigraphs:支持ISO C三字符组

    其他

    -D_REENTRANT(很重要)

    在一个多线程程序中,默认情况下,只有一个errno变量供所有的线程共享。在一个线程准备获取刚才的错误代码时,该变量很容易被另一个线程中的函数调用所改变。类似的问题还存在于fputs之类的函数中,这些函数通常用一个单独的全局性区域来缓存输出数据

    为解决这个问题,需要使用可重入的例程。可重入代码可以被多次调用而仍然工作正常。编写的多线程程序,通过定义宏_REENTRANT来告诉编译器我们需要可重入功能,这个宏的定义必须出现于程序中的任何#include语句之前。

    _REENTRANT为我们做三件事情,并且做的非常优雅:

    • 它会对部分函数重新定义它们的可安全重入的版本,这些函数名字一般不会发生改变,只是会在函数名后面添加_r字符串,如函数名gethostbyname变成gethostbyname_r。
    • stdio.h中原来以宏的形式实现的一些函数将变成可安全重入的函数
    • 在error.h中定义的变量error现在将成为一个函数调用,它能够以一种安全的多线程方式来获取真正的errno的值

    参考

    展开全文
    zhizhengguan 2020-12-26 14:52:17
  • 1.操作系统的软件堆栈、内存映射等区域配置,mmap、vdso页、共享库等, 实现方式:修改操作系统文件:/proc/sys/kernel/randomize_va_space,内容改为2。...2.软件堆栈保护 实现方式:编译时给gcc传参:

    1.操作系统的软件堆栈、内存映射等区域配置,mmap、vdso页、共享库等,

    实现方式:修改操作系统文件:/proc/sys/kernel/randomize_va_space,内容改为2。

    原因:ASLR针对缓冲区溢出攻击,此处将堆栈、共享库映射等内存地址随机化,增加难度。

    注意:randomize_va_space=1时表明栈、数据段、VDSO随机化,为2时表明堆栈、数据段、VDSO会随机化

    作用范围:Linux下的软件(包括用户、系统服务进程)

    2.软件堆栈保护

    实现方式:编译时给gcc传参:-fstack-protector-all/-fstack-protector-strong,其中-fstack-protector-strong保护范围最广

    原因:避免栈溢出被攻击,在缓冲区和控制信息间插入一个canary word,当缓冲区有溢出时,canary word会首先被覆盖,通过检测该字段实现防控 注意:windriver linux4.3 + MIPS环境不支持该操作

    作用范围:用户编译的*.o;*.so;*.out(elf可执行文件)

    3.软件链接库保护 

    实现方式:编译时给gcc传参:-Wl,-z,relro

    原因:动态链接的ELF二进制程序使用称为全局偏移表(GOT)的查找表去动态解析位于共享库中的函数,增加此选项可以避免被攻击者查找到函数入口进而防止被篡改执行函数

    注意:relro选项用于防护GOT表被修改 作用范围:用户编译的*.so;*.out(elf可执行文件)

    4.软件链接库保护

    实现方式:编译时给gcc传参:-Wl,-z,now

    原因:开启立即绑定,即在3的基础上开启立即绑定GOT全部表项只读模式。较好防控缓冲区溢出攻击。

    注意:该选项会导致软件启动性能下降, 但运行性能不受影响

    作用范围:用户动态库

    5.软件执行保护

    实现方式:编译时给gcc传参:-Wl,-z,noexecstack

    原因:缓冲区溢出的部分,锁定其数据段只读写,不可执行,即缓冲区溢出即时发生也不会执行恶意代码。

    注意:windriver linux 4.3普通版本不支持该特性;windriver linux 6 + MIPS不支持该特性 作用范围:用户软件及动态库等

    6.软件地址段保护 

    实现方式:编译时给gcc传参:-fPIC或-fpic

    原因:编译代码时将用户软件编译成与地址无关的代码段,使得用户应用加载so之后,地址空间根据用户的应用走,而非so内部指定的位置,减少被攻击可能性

    注意:-fPIC导致应用体积变大,-fpic产生的相对较小 作用范围:动态库(包括操作系统的库也要注意,不能拿来就用)

    7.软件地址段保护

    实现方式:编译时给gcc传参:–fPIE或-fpie及-pie

    原因:将可执行程序的地址编译成随机加载,不予以固定地址开始执行,降低攻击可能性

    注意:-fPIE产生代码稍大,-fpie产生代码相对较小;-fPIE编译选项,-pie链接选项 作用范围:动态库及可执行程序

    8.软件编译、运行时链接动态库保护:

    实现方式:gcc编译增加选项:-Wl,--disable-new-dtags,--rpath,/lib1:/lib2;-Wl,--enable-new-dtags,--rpath,/lib1:/lib2

    原因:默认情况下,gcc通过环境变量LD_LIBRARY_PATH读取用户库路径、系统库路径(运行时也一样),如果默认路径被篡改且具备同名动态库,则可能链接到攻击代码

    注意:文件系统路径需要存在

    作用范围:用户软件、系统软件(系统软件情况下就需要使用官方发布的版本、或者下载源码重新制作文件系统)

    9.软件编译、运行时静态区保护:

    实现方式:gcc编译增加选项:-D_FORTIFY_SOURCE=2 -O2

    原因:gcvc特性,对应用编译及运行静态区进行检查 注意:开销大,需要测试后使用

    作用范围:动态库、可执行文件

    10.软件动态库编译保护:

    实现方式:gcc编译增加选项:-fvisibility=hidden

    原因:设置elf文件的符号隐藏,可大幅提高链接加载性能

    注意:调试困难 作用范围:动态库、可执行文件

    11.软件运行堆栈保护:

    实现方式:gcc编译增加选项:-fstack-check

    原因:编译时检查应用的栈空间,如果超过编译告警阀值则产生告警;然后在程序中生成额外的指令来检查运行时栈不会被溢出,stack-check选项会在每个栈空间最低底部设置一个安全的缓冲区,如果函数中申请的栈空间进入安全缓冲区,则触发一个Storage_Error异常。但它所生成的代码实际上并不处理异常,如果检测到异常则会发出一个消息,通知操作系统处理。它只保证操作系统可以检测到栈扩展

    注意:性能影响大 作用范围:可执行文件

    12.软件调试符号保护:

    实现方式:gcc编译增加选项:-s或者用strip、objcopy工具进行分离(建议后者,后期调试gdb手动可加载)

    原因:符号表实际运行无用 注意:压缩后注意保存符号表文件

    作用范围:可执行、动态库

    13.Linux内核编译保护

     内核编译前打开配置 CONFIG_CC_STACKPROTECTOR / CONFIG_CC_STACKPROTECTOR_STRONG 内核3.14及以上版本可支持CONFIG_CC_STACKPROTECTOR_STRONG原有CONFIG_CC_STACKPROTECTOR(对应-fstack-protector)修改为CONFIG_CC_STACKPROTECTOR_REGULAR

    ------------------------分割线-------------------------

    3、4和5结合起来就是gcc传参:-Wl,-z,relro,-z,now,-z,noexecstack

    ------------------------分割线-------------------------

       缩写                           英文名                                    中文名

    VDSO     virtual dynamic shared object                虚拟动态共享对象

    ASLR     Address space layout randomization     地址空间分布随机

    GOT      global offset table                                      全局偏移量表

    PIC        position-independent code                        地址无关代码

    展开全文
    AMDDMA 2021-04-03 21:05:43
  • 代码管理工具,如git,代码编辑,sublime text,还有测试,网络安全等相关技术也是需要会一些。当然要求可能不会那么高,但至少要懂一些。所有今天准备了一些其他于前端相关的面试题供大家学习参考。希望对大家...

    我经常会听到一些想入行前端的人问,前端开发需要学习哪些技术?

    其实,除了核心的HTML、CSS、JavaScript技术外,像CSS预编译、前端框架,如Vue,React、Node、Angular;代码管理工具,如git,代码编辑器,sublime text,还有测试,网络安全等相关技术也是需要会一些。当然要求可能不会那么高,但至少要懂一些。所有今天准备了一些其他于前端相关的面试题供大家学习参考。希望对大家有所帮助。

    CSS预编译面试题

    在大型项目中,为了提高CSS的可维护性,人们开始使用CSS预编译技术。

    CSS预编译部分的面试题主要考察开发者对CSS预编译技术的使用。

    当然,CSS预编译技术中的变量、混合、方法、继承、作用域、语句、插值等也是应试者需要了解的。

    目前CSS预编译器主要有3种,分别是Less、 Sass、Stylus,应试者可以选择一种,了解它的使用方式。

    1、Scss是什么?有那几大特性?

    Sass和Scss其实是一样的css预处理语言,Scss是Sass3引入新的语法,其后缀名为.scss。Sass版本3.0之前的后缀名为.sass,而版本3.0之后的后缀名.scss。两者是有不同的,继Sass之后Scss的编写规范基本和css一致,Sass时代是有严格的缩进规范并且没有"{}“和”;",Sass使用缩进代替花括号,使用换行代替分号。 而Scss则使用"{}“和”;"。

    总结:sass是CSS预处理语言,scss是Sass语言中一套语法的拓展名。scss的特征是可以将CSS当作函数编写,可以定义变量,可以嵌套定义,可以使用语句等。

    2、安装和使用Sass的步骤是什么?

    具体步骤如下。

    • 通过npm安装css-loader、 node-loader、sass- loader等加载器模块。
    • 在 webpack .config. js配置文件中定义Sass加载器。

    3、Sass和Less有什么区别?

    区别如下。

    • 编译环境不一样。Sass的安装需要Ruby环境,是在服务器端处理的。而Less需要引入 less.js来处理,然后Less代码输岀CSS到浏览器中;也可以在开发环境中使用Less,然后编译成CSS文件,直接放到项目中运行。
    • 变量名不一样。Less中使用@,而Sass中使用$。
    • 插值语法不同,Less中使用@{key},Sass中使用#{$key}。
    • Sass的混合相当于Less的方法,Sass的继承相当于Less的混合。
    • 输出设置不同。Less没有输出设置。Sass提供4种输出选项:nested、compact、 compressed和 expanded。nested选项用于嵌套缩进的CSS代码(默认), expanded选项用于展开多行CSS代码, compact选项显示简洁格式的CSS代码, compressed选项显示压缩后的CSS代码。
    • Sass支持条件语句,如if…else、for循环等,而Less不支持。
    • 引用外部CSS文件的方式不同。Sass引用外部文件时必须以"_"开头,文件名用"_"命名,Sass会认为该文件是一个引用文件,不会将其编译为CSS文件。Less引用外部文件和CSS中的@ import没什么差异。
    • Sass和Less的工具库不同。Sass有工具库 Compass。简单说,Sass和 Compass的关系有点像 JavaScript和 jQuery的关系, Compass是Sass的工具库。在它的基础上,封装了一系列有用的模块和模板,补充和强化了Sass的功能。Less有UI组件库 Bootstrap, Bootstrap是Web前端开发中一个比较有名的前端UI组件库, Bootstrap中样式文件的部分源码就是采用Less语法编写的。

    总之,不管是Sass,还是Less,都可以将它们视为一种基于CSS之上的高级语言,其目的是使得CSS开发更灵活和更强大。Sass的功能比Less强大,可以认为Sass是种真正的编程语言;Less则相对清晰眀了,易于上手,对编译环境的要求比较宽松。

    4、什么是CSS预处理器/后处理器?

    预处理器(例如,Less、Sass、 Stylus)是用来把Sass或Less预编译成CSS的工具,増强了CSS代码的复用性。它有层级、 mixin、变量、循环、函数等,具有很方便的UI组件模块化开发能力,能极大地提高工作效率。

    后处理器(如 PostCSS)通常被视为在完成的样式表中根据CSS规范处理CSS,让其更有效。目前最常做的是给CSS属性添加浏览器私有前缀,解决跨浏览器兼容性的问题。

    版本管理工具面试题

    在多人开发中,势必要有一个理想的工具来管理每个人开发的代码,Git、SVN等就是这类版本控制工具的代表。版本控制工具部分的面试题主要考察应试者对版本控制工具的了解,例如,使用Git提交代码、解决冲突、发布到服务器端的方式,以及Git的架构理念、文件状态等。

    1、说说SVN和Git的区别?

    SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而开发的时候,用的都是自己的PC端。所以,首先要从中央服务器那里得到最新的版本,然后开发,旦开发任务完成后,需要把自己开发的文件推送到中央服务器。集中式版本控制系统必须联网才能工作,如果在局城网环境下带宽够大,速度够快,还是很方便的。但如果在互联网环境下网速很慢,就会严重影响开发效率Gⅱt是分布式版本控制系统,它没有中央服务器,每个人的PC就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本库都是在自己的PC上。每个人的PC都有一个完整的版本库,当多人协作开发的时候,只须把各自的修改文件推送给对方,就可以互相看到对方的修改了。

    2、说说Git中merge和rebase的区别?

    在Git中, merge和 rebase从最终效果来看没有任何区别,都是将不同分支的代码融合在一起,但是生成的代码树稍有不同。rebase操作不会生成新的节点,而是将两个分支融合成一个线性的提交。而 merge操作生成的代码树会显得比较乱。

    3、你都使用那些工具来测试代码性能?

    Profiler、 JSPerf等。

    4、如何管理你的项目代码?管理项目代码的过程中,大多使用命令行还是工具?

    在项目开发阶段就使用Git。在项目开始阶段,通常会单独拉取一个分支,在这个分支上开发新功能。做好之后让经理审核一下代码,如果代码没问题,他会把分支合并到主干上。

    当没有冲突的时候用命令行比较多。首先,在每次提交之前我会使用 Git pull拉取线上的代码,获取最新的代码。

    然后通过Git add,把新的代码写入缓冲区,再用 Git commit-m“备注”生成一个本地的版本,最后用 Git push推到线上库。

    5、Git fetch 和 Git pull的区别?

    Git pull相当于从远程获取最新版本并合并到本地;

    Git fetch相当于从远程获取最新版本并存放到本地,而不会自动合并。

    网络安全面试题

    网络安全是网站能够正常运行的保证,因此越来越多的人开始关注网络安全这一部分的内容。

    网络安全部分的面试题主要考察应试者对网络的认知,开发者需要了解常见的网络攻击方式,并在开发中避免漏洞。网络漏洞无法预知(如果能够预知新的漏洞就不会再有攻击者了),但是屏蔽掉已知的漏洞还是十分必要的。

    1、SQL注入是什么? 如何防护?

    SQL注入就是把SQL命令插入Web表单、输入域名或页面请求的查询字符串中,最终达到欺骗服务器执行恶意的SQL命令。

    总的来说,有以下几点防护措施。

    • 始终不要信任用户的输入,要对用户的输入进行校验,可以通过正则表达式或限制长度,对单引号和双“-”进行转换等。
    • 始终不要使用动态拼装SQL,可以使用参数化的SQL或者直接使用存储过程进行数据查询与存取。
    • 始终不要使用管理员权限的数据库连接,为每个应用使用单独的权限和有限的权限数据库连接,
    • 不要把机密信息用明文存放,应通过加密或者散列处理密码和敏感的信息。

    2、XSS攻击是什么? 如何防护?

    XSS( Cross Site Scripting)攻击指的是攻击者向Web页面里插入恶意HTML标签或者 JavaScript代码。比如,攻击者在论坛中放一个看似安全的链接,骗取用户单击并窃取 cookie中的用户私密信息;或者攻击者在论坛中加一个恶意表单,当用户提交表单的时候,却把信息传送到攻击者的服务器中,而不是用户原本以为的信任站点。

    要防范XSS攻击,首先,在代码里对用户输入的地方和变量都需要仔细检查长度和对“<” “>” “;” “ ’ ”等字符做过滤。其次,在把任何内容写到页面之前都必须进行编码,避免泄露 htmltag。在这一个层面做好,至少可以防止超过一半的XSS攻击。

    3、如何避免cookie信息被盗取?

    首先,避免直接在 cookie中泄露用户隐私,例如E-mai、密码等。

    其次,使 cookie和系统ip绑定,降低 cookie泄露后的危险。这样攻击者得到的cookie没有实际价值,不可能拿来重放。如果网站不需要在浏览器端对 cookie进行操作,可以在 Set-Cookie末尾加上 HttpOnly防止 JavaScript代码直接获取 cookie。

    最后,尽量采用POST请求方式而非GET请求方式提交表单。

    4、XSS攻击和CRSF攻击有什么区别?

    XSS攻击用于获取信息,不需要提前知道其他用户页面的代码和数据包。

    CSRF攻击用于代替用户完成指定的动作,需要知道其他用户页面的代码和数据包。

    5、如何防范CSRF攻击?

    要完成一次CSRF攻击,受害者必须依次完成两个步骤。

    (1)登录受信任网站A,并在本地生成 cookie。

    (2)在不登出A的情况下,访问危险网站B防范服务器端的CSRF攻击有很多种方法,但总的思想都是一致的,就是在客户端页面中增加伪随机数。

    6、你所了解的Web攻击技术有哪些?

    (1)XSS攻击:通过存在安全漏洞的Web网站,注册到用户的浏览器内,渲染非法的HTML标签或者运行非法的 JavaScript进行攻击的一种行为。

    (2)SQL注入攻击:通过把SQL命令插入Web表单、输入域名或页面请求的查询字符串中,最终达到欺骗服务器执行恶意的SQL命令。

    (3)CSRF攻击:攻击者通过设置陷阱,强制对已完成的认证用户进行非预期的个人信息或设定信息等状态的更新。

    展开全文
    qq_35568841 2021-04-08 14:27:31
  • 为更好地阅读本文,需要简单了解背景,建议可以大致浏览下前文:安全检测在线编译器中的安全检测,目的是确定用户代码是否能够安全的运行,且不对运行环境产生危害。仍以一般场景和特殊场景(前文有说明)举例区分:...

    此文已由作者姚太行授权网易云社区发布。

    欢迎访问网易云社区,了解更多网易技术产品运营经验。

    前文连接

    案例的介绍已在前文中给出,本文中对相关部分将不再叙述。为更好地阅读本文,需要简单了解背景,建议可以大致浏览下前文:

    安全检测

    在线编译器中的安全检测,目的是确定用户代码是否能够安全的运行,且不对运行环境产生危害。仍以一般场景和特殊场景(前文有说明)举例区分:一般场景:用户代码仅依赖原生库,运行环境选择沙箱情况下,沙箱间相互独立,用户代码导致的环境损害只会作用于单一沙箱,不会影响到其他沙箱及底层系统的正常使用。

    特殊场景:用户代码依赖平台提供API,运行环境无法使用独立的沙箱,用户代码不良操作可能会引起整个运行环境的异常,从而导致其他用户代码运行失败或服务器崩溃等情况。

    所以,在特殊场景下,如何对用户代码是否符合安全要求作出判定,是安全 检测的内容。

    在搭建一个合理的安全检测流程时,不能直接进入对代码分析的阶段,在此之前搞清楚用户代码生命周期涉及的各个阶段是必要的,只有充分了解被检测对象和检测目标的基础上,才能给出一个合理的流程:谁写的代码:代码编写的用户及用户形象

    代码写成什么样:代码语言、结构、内容等内容分析

    代码怎么用:代码运行、功能、效果等调用分析

    如何检测:设计合理检测流程

    用户形象 -“谁写的代码”

    用户形象及背景的分析,往往是在纯技术实现过程中容易忽略的问题。

    在一开始搭建网易贵金属量化平台的时候,大部分精力放置在基于用户代码本身的安全检测方案上,忽略了对用户角度的考虑,导致在没有对用户的形象及能力有一个正确评估的情形下构建的安全检测方案,总出现“出乎意料”、“覆盖不全”等情况,用户代码总超出预想范围。反思后,我们更换了切入点,先从用户形象和可能的行为入手,重新构思并设计了检测流程,使得检测的覆盖方面大大增加,实现起来也更为容易。

    用户形象,主要是明确代码编写的用户主体,究竟是以何种状态和知识水平参与到代码编写过程中的,需要明确的用户形象相关的内容主要可以涵盖:用户编程知识背景:用户是否具备相关编程语言的编程经验,以及编程语言的熟悉程度。最不利的假设,如果用户甚至没接触过对应的编程语言,直接在代码demo上做修改,一定会出现各种各样的错误。

    用户业务知识背景:用户是否具备代码涉及业务的知识背景,以及业务知识的掌握程度。特殊场景下,用户代码编写一业务背景相对较明确的代码时,如果对业务知识背景掌握不是很好,写出来的代码可能未必符合合理的逻辑。

    用户操作引导效果:用户是否会按照平台给出的引导进行操作。如果用户对帮助文档等引导未做到详细阅读以及完全理解,用户代码在结构和逻辑上可能都会出问题。

    用户意图:用户使用平台的意图是不明确的,有一定可能会存在恶意用户以破坏平台为目的,利用在线编译器进行破坏。

    对上述关注点,不能对用户的情况抱有幻想,所做的用户形象假设应考虑最不利的情况。简而言之:

    用户代码永远是不可信的。

    案例说明

    网易贵金属量化平台(上一篇文章中已做介绍),提供Java在线编译器,用户代码内容为量化投资策略逻辑描述,用户形象中构想的一些不利情况下的假设:用户背景不尽相同,有些用户之前可能未接触过Java,不能奢求代码语法合法性

    用户技术水平是参差不齐的,代码写成什么样都有可能,不能奢求代码规范

    即便是帮助文档写的再好,用户也未必会看的完全,不能奢求代码操作合理性

    用户未必会按照你的要求规范,老老实实按照给出的Demo流程书写,不能奢求代码符合预定流程

    用户未必清楚一个量化策略从何开始、到哪结束、需要包含什么内容,不能奢求代码逻辑合理性

    可能出现一些恶意用户,目的就是来搞破坏的,不能奢求代码安全性

    首先把用户代码可能触发安全问题的原因明确后,再根据不同的原因设计对应的解决方案,就会大大提升安全检测流程的有效性。

    代码内容分析 -“代码写成什么样”

    代码内容分析,主要是分析代码涉及的内容、结构等方面的情况,以方便在未获得用户代码之前,对用户代码可能涉及和存在的内容作出预判,从而构思应对思路,关注点涵盖:代码结构:以Java为例,可以明确是否以类为主体,是否包含必要的方法,是否有明确的方法结构

    业务逻辑:代码本身是否存在明确的业务逻辑结构

    包含引用:代码是否必须引用其他类,或者类中的某个方法

    数据交互:用户代码和平台间存在哪些涉及到数据交互的内容,输入输出的内容。

    以上的关注点明确后,配合平台在用户代码构建阶段对代码结构的固定,基本可以在用户代码获得前,明确用户代码的大致过程。

    案例说明

    网易贵金属量化平台,代码结构固定,必须实现策略类模板接口(上一篇文章有介绍),业务逻辑上非常明确,策略代码的行为抽象主要包含:

    a07e6ae6cea874488863df932ca19066.png

    通过对策略代码的行为抽象,即可明确代码所包含的所有业务、业务对应类引用以及会产生数据交互的内容。上图中将行为抽象为树结构,对行为点以范畴进行区分,并明确标记输入(I)、输出(O)等产生数据交互的关注点,以便之后根据此构建代码检测流程。

    代码使用分析 -“代码怎么用”

    用户代码最终需要加载至运行环境进行调用的,在平台调用用户代码的过程中,调用细节也会影响到安全检测的规划及构思细节。关于使用分析的关注点,可以从以下方面考虑:编译过程:编译过程细节语言是否需要编译

    编译是否伴随诊断,而诊断过程中包含的诊断内容

    编译结果存储形式(文件、数据库或内存)

    调用过程:平台调用细节调用用户代码中的何类

    调用用户代码中的何方法

    调用方式(一次性调用、循环触发、定时触发、事件触发等)

    调用期间数据交互(内容分析基础上,分析数据最初来源及最终流向,文件、数据库、内存等)

    运行结束:结束用户代码留存情况调用后是否会被平台用作其他功用

    调用后代码编译类是否会被类加载器剔除

    调用后用户代码是否还会留存在系统内

    通过使用分析,可以规划出在整个生命周期内,用户代码跟平台产生交互的部分,这些不同层次的交互中可能会对系统安全产生威胁,故在安全检测流程设计时,应结合不同的交互层次给出不同检测策略。

    案例说明

    网易贵金属量化平台(前文对案例有所介绍),在使用分析的流程上大概可简述为:编译过程:Java语言,需要进行编译,编译过程伴随诊断,最终编译结果以类字节码的形式存在,无需落地

    调用过程:用户代码为策略类的实现,调用时,该类被加载至服务器的类加载器。

    调用策略类中的init方法以完成该策略类对象初始化、循环调用handle方法以在行情的每一个调度周期内完成相应动作、最终调用onExit方法来完成策略调用过程。

    数据交互上,用户策略类在使用过程中,会读取内存中的行情信息,并根据策略逻辑内容产生交易信息(开仓信息、平仓信息)。

    运行结束:用户代码在调用后,用户策略类将不会做其他使用,类加载器中将把该类从加载器中剔除,策略类的实例对象将会被GC回收。

    安全检测流程 -“如何检测”

    上述流程后,用户代码的生命周期及使用场景基本描绘完全,可根据具体场景构建安全检测流程。

    布局

    不要奢求安全检测能够一次性完成,即便是一次性能够实现安全检测的目的,代价上也是得不偿失的。

    安全检测应分布于代码生命周期的各个阶段。

    能够一次性检测的方法,理论上一定会部署在整个代码生命周期内足够靠后的位置,一旦用户代码被检测出安全问题不在被平台运行时,之前的所有操作都是白费的;如果采用将安全检测分布于生命周期的各个阶段的方案,不同阶段解决不同的安全检测问题,能够尽早发现代码的安全问题,从而尽早打断,减少不必要的操作以及资源消耗。

    检测内容及目的

    简而言之,检测的目的就是:保证用户代码仅在允许范围内可用。

    以此为根本目的,检测内容的关注点可包含:用户代码是否使用了规定范围外的类

    用户代码是否使用了规定范围外的方法

    用户代码是否存在了规定范围外的行为

    用户代码是否存在了不易检测的不良行为(大内存使用、长时间线程占用)

    以上内容相对较为抽象,后文将结合具体案例,对使用到的相关技术及具体细节作出介绍。

    案例说明

    网易贵金属量化平台,随着对Java在线编译器认知的不断加深,安全检测流程也在不断的健全。

    最简单的版本

    用户可以自主导入JDK相关包,平台补充API相关包。源代码生成后,利用JavaComplier中的诊断信息,即能完全判定某策略类是否在当前的项目环境中可运行的。

    面临的问题:未对import导入的包做限制,用户可使用JDK所有类

    即便对import做限制后,默认导入的java.lang以及当前类所在包是默认导入的,其中的类无法限制导入

    导致的问题:用户可以使用System等系统相关类,影响系统状态

    用户可以向外部发送网络请求

    用户可以自己创建线程

    ...

    更新后的检测流程

    通过对用户代码的内容分析、运行分析后,得出这样一个结论:如果只希望用户使用平台提供的服务与行为,就必须限制其余行为,但行为的执行实质就是“方法”,但方法的执行主体是“类及对象”,所以“限制行为的实质就是限制类使用”。

    以此认识为核心,并按照将检测流程分布在代码生命周期的各个阶段的思想,量化平台规划出的检测流程如下:

    e9f3f1aa993bce8b93911648ea4a48ca.png

    检测流程被分布在了编译前、编译时、编译后的各个流程内,具体内容包括:编译前-编译预检:指定所有编译后的类所在包路径

    检测文件是否为空

    检测文件是否单独进行包导入

    检测文件是否包含策略模板接口实现类

    检测类是否唯一以及是否存在内部类

    代码简单词法分析:

    代码存放位置限定:

    编译时-编译诊断:获得类源代码编译过程中的诊断信息,判定是否存在诊断

    编译后-结果检查:对编译后的.class字节码进行解析,找到其中涉及到的所有类,进行安全类列表的白名单检查

    类列表安全检查:

    对于编译前及编译时涉及到的检测内容,在前文《代码在线编译器(上)- 编辑及编译》中均有过详细的介绍,这里主要介绍下类列表安全检查的相关内容。

    类列表安全检查

    目的就是,找到用户策略中所有涉及到的类,与类白名单进行比对,验证这些类是否均在白名单内,如果出现了名单外的类,认为用户代码不安全,可拒绝运行,并给用户作出反馈。

    类白名单

    类白名单中的类来自两部分:平台提供的API所涉及的类

    必须使用的JDK中的类(java.lang中的类也要单独指明,java.lang中不是所有类都可用)

    三方工具包中的类

    获得涉及类

    在获得用户代码所有涉及类的过程中,思路有两种:从源代码进行分析:利用编译原理中的抽象语法树(Abstract Syntax Tree)

    从字节码进行分析:利用Java字节码框架,直接分析字节码构成。

    class类字节码作为代码编译后最终体现,可以反馈实际用到的所有类,实际实现过程中,也是选用此方案进行实施的。

    使用的字节码框架为ASM。

    ASM使用

    简介

    ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class 文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据要求生成新类。ASM最常用的使用场景就是静态AOP的实现(例如CGLIB)。

    本文使用ASM,分析类信息,从而提炼出类字节码中使用涉及到的所有类。

    class文件结构

    在分析class文件之前,先对class结构作出简要介绍:

    1540871326135429.jpg

    文件各部分含义如下:Magic:该项存放了一个 Java 类文件的魔数(magic number)和版本信息。一个 Java 类文件的前 4 个字节被称为它的魔数。每个正确的 Java 类文件都是以 0xCAFEBABE 开头的,这样保证了 Java 虚拟机能很轻松的分辨出 Java 文件和非 Java 文件。

    Version:该项存放了 Java 类文件的版本信息。

    Constant Pool:该项存放了类中各种文字字符串、类名、方法名和接口名称、final变量以及对外部类的引用信息等常量。虚拟机必须为每一个被装载的类维护一个常量池,常量池中存储了相应类型所用到的所有类型、字段和方法的符号引用。

    Access_flag:该项指明了该文件中定义的是类还是接口(一个class文件中只能有一个类或接口),同时还指名了类或接口的访问标志,如 public,private, abstract 等信息。

    This Class:指向表示该类全限定名称的字符串常量的指针。

    Super Class:指向表示父类全限定名称的字符串常量的指针。

    Interfaces:一个指针数组,存放了该类或父类实现的所有接口名称的字符串常量的指针。

    Fields:该项对类或接口中声明的字段进行了细致的描述,仅列出了本类或接口中的字段,并不包括从超类和父接口继承而来的字段。

    Methods:该项对类或接口中声明的方法进行了细致的描述。例如方法的名称、参数和返回值类型等。需要注意的是,methods 列表里仅存放了本类或本接口中的方法,并不包括从超类和父接口继承而来的方法。

    Class attributes:该项存放了在该文件中类或接口所定义的属性的基本信息。

    在这些内容中涉及到类名的部分为Fileds和Methods,需使用ASM对这一部分内容进行浏览。class文件内容获取

    以一段简单的包含Fields和Methods的代码为例,说明一下类在字节码中的体现形式。

    源码public class IniBean {private static Logger logger = LoggerFactory.getLogger("inibean");private static AtomicBoolean initFlag = new AtomicBoolean(true);@PostConstructpublic void init() {

    logger.info("[IniBean] init method invoke.");if (initFlag.getAndSet(false)) {

    refreshIniInfo();

    }

    }

    ...

    编译后字节码public void init();

    Code:       0: getstatic     #2                  // Field logger:Lorg/slf4j/Logger;

    3: ldc           #3                  // String [IniBean] init method invoke.

    5: invokeinterface #4,  2            // InterfaceMethod org/slf4j/Logger.info:(Ljava/lang/String;)V

    10: getstatic     #5                  // Field initFlag:Ljava/util/concurrent/atomic/AtomicBoolean;

    13: iconst_0      14: invokevirtual #6                  // Method java/util/concurrent/atomic/AtomicBoolean.getAndSet:(Z)Z

    17: ifeq          24

    20: aload_0      21: invokevirtual #7                  // Method refreshIniInfo:()V

    24: return

    编译后的字节码中,类名以文件结构(注意此处不是“.”而是以“/”分割的路径,通过class.getClassName()获得的是以“.”分割的类包路径,比对前需要注意转换)进行体现,利用ASM浏览类文件字节码即可获得涉及的类列表。

    ASM过程关键类说明

    简要说明几个用到的关键类:org.objectweb.asm.ClassVisitor/**

    * A visitor to visit a Java class. The methods of this class must be called in

    * the following order: visit [ visitSource ] [

    visitOuterClass ] ( visitAnnotation |

    visitTypeAnnotation | visitAttribute )* (

    visitInnerClass | visitField | visitMethod )*

    visitEnd.

    *

    类访问器,用于访问类节点。

    org.objectweb.asm.ClassReader/**

    * A Java class parser to make a {@link ClassVisitor} visit an existing class.

    * This class parses a byte array conforming to the Java class file format and

    * calls the appropriate visit methods of a given class visitor for each field,

    * method and bytecode instruction encountered.

    *

    ...

    用于读入类字节码相关内容,并提供内部元素访问方法。

    org.objectweb.asm.tree.ClassNode/**

    * A node that represents a class.

    *

    表示一个类,与class文件结构对应,继承于org.objectweb.asm.ClassVisitor。

    org.objectweb.asm.ClassWriter/**

    * A {@link ClassVisitor} that generates classes in bytecode form. More

    * precisely this visitor generates a byte array conforming to the Java class

    * file format. It can be used alone, to generate a Java class "from scratch",

    * or with one or more {@link ClassReader ClassReader} and adapter class visitor

    * to generate a modified class from one or more existing Java classes.

    *

    类写入器,并提供了类逐行扫描的过程。流程简述读入类字节码内容内容ClassReader cr = new ClassReader(classByte);

    生成类节点对象ClassNode、类编写器ClassWriter(用于使用AbstractInsnNode)this.classNode = new ClassNode();// 初始化classNode-进行类结构粗扫描classReader.accept(classNode, ClassReader.SKIP_DEBUG);// 初始化ASMClassAdapter-进行方法内逐行扫描ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);

    classAdapter = new ASMClassAdapter(cw);

    classReader.accept(classAdapter, ClassReader.SKIP_DEBUG);

    3.遍历Fieldsprivate Set getClassInFields() {

    Set result = new HashSet<>();// 0.0 获得所有属性List fieldList = this.classNode.fields;for (FieldNode fieldNode : fieldList) {// 1.0 获得类名String classNameStr = Type.getType(fieldNode.desc).getClassName();// 2.0 将真实类名填写到类列表内result.add(ASMConstant.pickClassName(classNameStr));

    }return result;

    }

    4.遍历所有Methodsprivate Set getClassInMethods() {

    Set result = new HashSet<>();// 0.0 获得所有方法List methodList = this.classNode.methods;for (MethodNode methodNode : methodList) { // 1.1 如果是构造方法,则捕获当前类类型

    if(ASMConstant.METHOD_TYPE_INIT.equals(methodNode.name)){

    result.add(ASMConstant.pickClassName(this.classNode.name.replaceAll("\\/", "\\.")));

    }

    // 1.2 提取参数

    for(Type argumentType : Type.getArgumentTypes(methodNode.desc)){

    result.add(ASMConstant.pickClassName(argumentType.getClassName()));

    } // 1.3 提取局部变量

    List lvNodeList = methodNode.localVariables; for (LocalVariableNode lvn : lvNodeList) {

    result.add(ASMConstant.pickClassName(Type.getType(lvn.desc).getClassName()));

    }

    }return result;

    }

    5.Methods内逐行遍历(前一步只对Methods声明作出遍历)public void visitInsn(int opcode) {

    Iterator itr = this.instructions.iterator(0);while (itr.hasNext()) {

    AbstractInsnNode insn = itr.next();switch (insn.getType()) {case AbstractInsnNode.FIELD_INSN:// 1.0 方法内局部变量String fieldInsnDesc = ((FieldInsnNode) insn).desc;// 1.1 获得类名String classNameStr = ASMConstant.pickClassName(Type.getType(fieldInsnDesc).getClassName());// 1.2 将真实类名填写到类列表内this.classSet.add(classNameStr);break;case AbstractInsnNode.METHOD_INSN:// 2.0 方法内调用的方法String methodInsnOwner = ((MethodInsnNode) insn).owner;// 2.1 名称转换    this.classSet.add(ASMConstant.pickClassName(methodInsnOwner.replaceAll("\\/", "\\.")));break; case AbstractInsnNode.TYPE_INSN:// 3.0方法内调用的类型String typeInsnDesc = ((TypeInsnNode) insn).desc;this.classSet.add(ASMConstant.pickClassName(typeInsnDesc.replaceAll("\\/", "\\.")));break;

    ...

    经历以上过程汇总后,即可获得某类字节码中涉及的所有类列表,再与明确构建的白名单列表作出比对,即可验证类使用范畴的安全性。

    心得

    工程实践积累经验,不但需要在过程中提高熟练度,更需要从实践中抽象模型、整理思路、总结理论,追求技术中由“技”到“术”获得的沉淀。

    更多网易技术、产品、运营经验分享请点击。

    展开全文
    weixin_29457191 2021-03-08 23:00:57
  • weixin_29173777 2021-05-14 20:57:54
  • weixin_39630106 2021-05-26 17:45:47
  • weixin_39943926 2020-12-21 21:47:58
  • snsHL9db69ccu1aIKl9r 2021-03-23 00:05:04
  • qq_37213281 2021-09-02 12:02:25
  • zouhui1003it 2021-02-04 21:28:38
  • han1202012 2021-04-21 13:07:25
  • weixin_46662141 2021-04-01 09:05:39
  • qq_45966201 2021-01-23 16:03:26
  • weixin_44972008 2021-11-29 16:37:14
  • weixin_30953203 2021-05-11 19:38:20
  • Ivan804638781 2021-11-28 04:06:48
  • u011426115 2021-01-01 22:54:19
  • weixin_42361622 2021-03-26 14:12:52
  • smellycat000 2021-08-11 00:37:21
  • weixin_30113867 2021-05-17 16:22:36
  • weixin_29661407 2021-03-16 23:22:27
  • qf2019 2021-11-16 11:26:04
  • weixin_32019577 2021-06-07 06:49:04
  • yao_hou 2021-09-04 17:50:22
  • sherlockmj 2021-03-17 14:27:02
  • qq_43148810 2021-10-26 14:17:28
  • weixin_44211968 2021-11-11 16:45:42
  • bloodzero_new 2021-01-16 22:11:36
  • shebao3333 2021-01-15 09:28:28
  • weixin_44498318 2021-03-24 20:19:15

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 132,117
精华内容 52,846
关键字:

安全编译选项检查工具