技术背景

在一些对python开源库代码的安全扫描中,我们有可能需要分析库中所使用到的函数是否会对代码的执行环境造成一些非预期的影响。典型的例如python的沙箱逃逸问题,通过一些python的第三方库可以执行系统shell命令,而这就不在python的沙箱防护范围之内了。关于python的沙箱逃逸问题,这里不作展开,这也是困扰业界多年的一个问题,连python官方也提过python的沙箱是没有完美的防护方案的,这里仅作为一个背景案例使用:

# subprocess_Popen.py

import subprocess
import uuid

subprocess.Popen('touch ' + str(uuid.uuid1()) +'.txt', shell = True) 

这里演示的功能是使用subprocess函数库开启一个系统shell,并执行一个touch的指令,可以生成一个指定文件名的文件,类似于mkdir产生一个文件夹。我们可以看到这个文件成功执行后会在当前的目录下生成一个uuid随机命名的txt文件:

[dechin@dechin-manjaro bandit_test]$ python3 subprocess_Popen.py 
[dechin@dechin-manjaro bandit_test]$ ll
总用量 4
-rw-r--r-- 1 dechin dechin   0  1月 26 23:03 b7aa0fc8-5fe7-11eb-b5d3-058313e110e4.txt
-rw-r--r-- 1 dechin dechin 123  1月 26 23:03 subprocess_Popen.py 

然而,本次的关注点并不在与这个函数执行了什么功能,而是这个函数中用到了subprocess这个函数库。按照python的语言特点,当你的系统中如果存在这样的一个模块引用了subprocess库,那么任何可以调用该功能模块的函数,都可以调用到subprocess这个函数,以下是另外一个恶意用户的python代码

# bad.py

from subprocess_Popen import subprocess as subprocess

subprocess.Popen('touch bad.txt', shell = True) 

该代码的目的是在不直接import subprocess的条件下,通过前面创建好的subprocess_Popen.py来进行搭桥调用subprocess的功能函数。这个脚本的执行结果如下:

[dechin@dechin-manjaro bandit_test]$ python3 bad.py 
[dechin@dechin-manjaro bandit_test]$ ll
总用量 12
-rw-r--r-- 1 dechin dechin    0  1月 26 23:13 0fda7ede-5fe9-11eb-80a8-ad279ab4e0a6.txt
-rw-r--r-- 1 dechin dechin    0  1月 26 23:03 b7aa0fc8-5fe7-11eb-b5d3-058313e110e4.txt
-rw-r--r-- 1 dechin dechin  113  1月 26 23:13 bad.py
-rw-r--r-- 1 dechin dechin    0  1月 26 23:13 bad.txt
drwxr-xr-x 2 dechin dechin 4096  1月 26 23:13 __pycache__
-rw-r--r-- 1 dechin dechin  123  1月 26 23:03 subprocess_Popen.py 

这个结果意味着,我们成功的使用bad.py调用了subprocess_Popen.py中所引用的subprocess,成功touch了一个bad.txt的文件。

到这里我们的背景案例演示结束,但我们需要重新梳理这些案例中所包含的逻辑:我们原本是希望在自己的系统中不引入python的沙箱逃逸问题,我们会对其他人传递过来的代码进行扫描,如使用下文中将要介绍的bandit工具来屏蔽subprocess等"危险函数"。而如果我们在自己写的python库或者引入的第三方python库中存在类似于subprocess的引用,这就会导致我们的屏蔽失效,用户可以任意的通过这些引用的搭桥直接调用subprocess的函数功能。因此,在特殊的条件要求下,我们需要对自己的代码进行安全函数扫描,以免为其他人的系统带来不可预期的安全风险。bandit只是其中的一种安全函数扫描的工具,接下来我们介绍一下其基本安装和使用方法。

用pip安装bandit

这里直接使用pip来安装bandit,有需要的也可以从源码直接安装。关于在pip的使用中配置国内镜像源的方法,可以参考这篇博客中对python安装第三方库的介绍。

[dechin@dechin-manjaro bandit_test]$ python3 -m pip install bandit
Collecting bandit
  Downloading bandit-1.7.0-py3-none-any.whl (115 kB)
     |████████████████████████████████| 115 kB 101 kB/s 
Requirement already satisfied: PyYAML>=5.3.1 in /home/dechin/anaconda3/lib/python3.8/site-packages (from bandit) (5.3.1)
Collecting GitPython>=1.0.1
  Downloading GitPython-3.1.12-py3-none-any.whl (159 kB)
     |████████████████████████████████| 159 kB 28 kB/s 
Requirement already satisfied: six>=1.10.0 in /home/dechin/anaconda3/lib/python3.8/site-packages (from bandit) (1.15.0)
Collecting stevedore>=1.20.0
  Downloading stevedore-3.3.0-py3-none-any.whl (49 kB)
     |████████████████████████████████| 49 kB 25 kB/s 
Collecting gitdb<5,>=4.0.1
  Downloading gitdb-4.0.5-py3-none-any.whl (63 kB)
     |████████████████████████████████| 63 kB 28 kB/s 
Collecting pbr!=2.1.0,>=2.0.0
  Downloading pbr-5.5.1-py2.py3-none-any.whl (106 kB)
     |████████████████████████████████| 106 kB 26 kB/s 
Collecting smmap<4,>=3.0.1
  Downloading smmap-3.0.5-py2.py3-none-any.whl (25 kB)
Installing collected packages: smmap, gitdb, GitPython, pbr, stevedore, bandit
Successfully installed GitPython-3.1.12 bandit-1.7.0 gitdb-4.0.5 pbr-5.5.1 smmap-3.0.5 stevedore-3.3.0 

安装结束之后,可以通过以下指令验证是否安装成功:

[dechin@dechin-manjaro bandit_test]$ bandit -h
usage: bandit [-h] [-r] [-a {file,vuln}] [-n CONTEXT_LINES] [-c CONFIG_FILE] [-p PROFILE] [-t TESTS] [-s SKIPS] [-l] [-i] [-f {csv,custom,html,json,screen,txt,xml,yaml}] [--msg-template MSG_TEMPLATE] [-o [OUTPUT_FILE]] [-v] [-d] [-q]
              [--ignore-nosec] [-x EXCLUDED_PATHS] [-b BASELINE] [--ini INI_PATH] [--exit-zero] [--version]
              [targets [targets ...]]

Bandit - a Python source code security analyzer

positional arguments:
  targets               source file(s) or directory(s) to be tested

optional arguments:
  -h, --help            show this help message and exit
  -r, --recursive       find and process files in subdirectories
  -a {file,vuln}, --aggregate {file,vuln}
                        aggregate output by vulnerability (default) or by filename
  -n CONTEXT_LINES, --number CONTEXT_LINES
                        maximum number of code lines to output for each issue
  -c CONFIG_FILE, --configfile CONFIG_FILE
                        optional config file to use for selecting plugins and overriding defaults
  -p PROFILE, --profile PROFILE
                        profile to use (defaults to executing all tests)
  -t TESTS, --tests TESTS
                        comma-separated list of test IDs to run
  -s SKIPS, --skip SKIPS
                        comma-separated list of test IDs to skip
  -l, --level           report only issues of a given severity level or higher (-l for LOW, -ll for MEDIUM, -lll for HIGH)
  -i, --confidence      report only issues of a given confidence level or higher (-i for LOW, -ii for MEDIUM, -iii for HIGH)
  -f {csv,custom,html,json,screen,txt,xml,yaml}, --format {csv,custom,html,json,screen,txt,xml,yaml}
                        specify output format
  --msg-template MSG_TEMPLATE
                        specify output message template (only usable with --format custom), see CUSTOM FORMAT section for list of available values
  -o [OUTPUT_FILE], --output [OUTPUT_FILE]
                        write report to filename
  -v, --verbose         output extra information like excluded and included files
  -d, --debug           turn on debug mode
  -q, --quiet, --silent
                        only show output in the case of an error
  --ignore-nosec        do not skip lines with # nosec comments
  -x EXCLUDED_PATHS, --exclude EXCLUDED_PATHS
                        comma-separated list of paths (glob patterns supported) to exclude from scan (note that these are in addition to the excluded paths provided in the config file) (default:
                        .svn,CVS,.bzr,.hg,.git,__pycache__,.tox,.eggs,*.egg)
  -b BASELINE, --baseline BASELINE
                        path of a baseline report to compare against (only JSON-formatted files are accepted)
  --ini INI_PATH        path to a .bandit file that supplies command line arguments
  --exit-zero           exit with 0, even with results found
  --version             show program's version number and exit

CUSTOM FORMATTING
-----------------

Available tags:

    {abspath}, {relpath}, {line},  {test_id},
    {severity}, {msg}, {confidence}, {range}

Example usage:

    Default template:
    bandit -r examples/ --format custom --msg-template     "{abspath}:{line}: {test_id}[bandit]: {severity}: {msg}"

    Provides same output as:
    bandit -r examples/ --format custom

    Tags can also be formatted in python string.format() style:
    bandit -r examples/ --format custom --msg-template     "{relpath:20.20s}: {line:03}: {test_id:^8}: DEFECT: {msg:>20}"

    See python documentation for more information about formatting style:
    https://docs.python.org/3/library/string.html

The following tests were discovered and loaded:
-----------------------------------------------
        B101    assert_used
        B102    exec_used
        B103    set_bad_file_permissions
        B104    hardcoded_bind_all_interfaces
        B105    hardcoded_password_string
        B106    hardcoded_password_funcarg
        B107    hardcoded_password_default
        B108    hardcoded_tmp_directory
        B110    try_except_pass
        B112    try_except_continue
        B201    flask_debug_true
        B301    pickle
        B302    marshal
        B303    md5
        B304    ciphers
        B305    cipher_modes
        B306    mktemp_q
        B307    eval
        B308    mark_safe
        B309    httpsconnection
        B310    urllib_urlopen
        B311    random
        B312    telnetlib
        B313    xml_bad_cElementTree
        B314    xml_bad_ElementTree
        B315    xml_bad_expatreader
        B316    xml_bad_expatbuilder
        B317    xml_bad_sax
        B318    xml_bad_minidom
        B319    xml_bad_pulldom
        B320    xml_bad_etree
        B321    ftplib
        B323    unverified_context
        B324    hashlib_new_insecure_functions
        B325    tempnam
        B401    import_telnetlib
        B402    import_ftplib
        B403    import_pickle
        B404    import_subprocess
        B405    import_xml_etree
        B406    import_xml_sax
        B407    import_xml_expat
        B408    import_xml_minidom
        B409    import_xml_pulldom
        B410    import_lxml
        B411    import_xmlrpclib
        B412    import_httpoxy
        B413    import_pycrypto
        B501    request_with_no_cert_validation
        B502    ssl_with_bad_version
        B503    ssl_with_bad_defaults
        B504    ssl_with_no_version
        B505    weak_cryptographic_key
        B506    yaml_load
        B507    ssh_no_host_key_verification
        B601    paramiko_calls
        B602    subprocess_popen_with_shell_equals_true
        B603    subprocess_without_shell_equals_true
        B604    any_other_function_with_shell_equals_true
        B605    start_process_with_a_shell
        B606    start_process_with_no_shell
        B607    start_process_with_partial_path
        B608    hardcoded_sql_expressions
        B609    linux_commands_wildcard_injection
        B610    django_extra_used
        B611    django_rawsql_used
        B701    jinja2_autoescape_false
        B702    use_of_mako_templates
        B703    django_mark_safe 

从这个列表中的屏蔽函数我们可以看出所谓的"危险函数"到底都有哪些,比如常用的subprocessrandom都被包含在内。subprocess是因为其对shell的调用而被列为"危险函数",而random则是因为其伪随机数的性质(这里简单说明一下,现在一般推荐使用secrets中的所谓安全随机数,但是实际上只有量子叠加测量才能够真正实现真随机数)。

bandit常用使用方法

  1. 直接对py文件进行扫描:
[dechin@dechin-manjaro bandit_test]$ bandit subprocess_Popen.py 
[main]  INFO    profile include tests: None
[main]  INFO    profile exclude tests: None
[main]  INFO    cli include tests: None
[main]  INFO    cli exclude tests: None
[main]  INFO    running on Python 3.8.5
[node_visitor]  INFO    Unable to find qualified name for module: subprocess_Popen.py
Run started:2021-01-26 15:31:00.425603

Test results:
>> Issue: [B404:blacklist] Consider possible security implications associated with subprocess module.
   Severity: Low   Confidence: High
   Location: subprocess_Popen.py:3
   More Info: https://bandit.readthedocs.io/en/latest/blacklists/blacklist_imports.html#b404-import-subprocess
2
3       import subprocess
4       import uuid

--------------------------------------------------
>> Issue: [B602:subprocess_popen_with_shell_equals_true] subprocess call with shell=True identified, security issue.
   Severity: High   Confidence: High
   Location: subprocess_Popen.py:6
   More Info: https://bandit.readthedocs.io/en/latest/plugins/b602_subprocess_popen_with_shell_equals_true.html
5
6       subprocess.Popen('touch ' + str(uuid.uuid1()) +'.txt', shell = True)

--------------------------------------------------

Code scanned:
        Total lines of code: 3
        Total lines skipped (#nosec): 0

Run metrics:
        Total issues (by severity):
                Undefined: 0.0
                Low: 1.0
                Medium: 0.0
                High: 1.0
        Total issues (by confidence):
                Undefined: 0.0
                Low: 0.0
                Medium: 0.0
                High: 2.0
Files skipped (0): 

通过对刚才所创建的调用了危险函数subprocess的py文件subprocess_Popen.py的扫描,我们识别出了其中的"危险函数",注意这里的Issue编号是602,定级是Severity: Low Confidence: High。但是如果我们用bandit去扫描利用了其他函数对危险函数的调用搭桥来二次调用的bad.py文件,我们发现是另外一种结果:

[dechin@dechin-manjaro bandit_test]$ bandit bad.py 
[main]  INFO    profile include tests: None
[main]  INFO    profile exclude tests: None
[main]  INFO    cli include tests: None
[main]  INFO    cli exclude tests: None
[main]  INFO    running on Python 3.8.5
[node_visitor]  INFO    Unable to find qualified name for module: bad.py
Run started:2021-01-26 15:30:47.370468

Test results:                                                                                                                                                                                                                               
>> Issue: [B404:blacklist] Consider possible security implications associated with subprocess module.
   Severity: Low   Confidence: High                                                                                                                                                                                                         
   Location: bad.py:3                                                                                                                                                                                                                       
   More Info: https://bandit.readthedocs.io/en/latest/blacklists/blacklist_imports.html#b404-import-subprocess                                                                                                                              
2
3       from subprocess_Popen import subprocess as subprocess
4
5       subprocess.Popen('touch bad.txt', shell = True)

--------------------------------------------------
>> Issue: [B604:any_other_function_with_shell_equals_true] Function call with shell=True parameter identified, possible security issue.
   Severity: Medium   Confidence: Low                                                                                                                                                                                                       
   Location: bad.py:5                                                                                                                                                                                                                       
   More Info: https://bandit.readthedocs.io/en/latest/plugins/b604_any_other_function_with_shell_equals_true.html                                                                                                                           
4
5       subprocess.Popen('touch bad.txt', shell = True)

--------------------------------------------------

Code scanned:                                                                                                                                                                                                                               
        Total lines of code: 2
        Total lines skipped (#nosec): 0

Run metrics:                                                                                                                                                                                                                                
        Total issues (by severity):
                Undefined: 0.0
                Low: 1.0
                Medium: 1.0
                High: 0.0
        Total issues (by confidence):
                Undefined: 0.0
                Low: 1.0
                Medium: 0.0
                High: 1.0
Files skipped (0): 

注意这里虽然实现的功能跟上面那个例子是一样的,但是这里的Issue编号为604,定级也变成了Severity: Medium Confidence: Low。这里的关键并不是定级变成了什么,而是定级被改变了,这是因为bandit是通过对字符串的处理来识别危险函数的,因此对于这种二次调用的特殊场景,bandit不一定都能够准确的识别出来对危险函数的调用,甚至可能出现二次调用后,完全无法识别风险函数的使用的可能性。

  1. 扫描一个目录下的所有py文件,并将结果写入txt文件
[dechin@dechin-manjaro bandit_test]$ bandit *.py -o test_bandit.txt -f txt
[main]  INFO    profile include tests: None
[main]  INFO    profile exclude tests: None
[main]  INFO    cli include tests: None
[main]  INFO    cli exclude tests: None
[main]  INFO    running on Python 3.8.5
[node_visitor]  INFO    Unable to find qualified name for module: bad.py
[node_visitor]  INFO    Unable to find qualified name for module: subprocess_Popen.py
[text]  INFO    Text output written to file: test_bandit.txt 

该案例就扫描了当前目录下的所有py文件,其实就是bad.pysubprocess_Popen.py这两个,并且将最终的扫描结果保存至test_bandit.txt文件中,这里我们就不展示txt文件的具体内容,大概就是将上一章节的两个执行结果进行了整合。

  1. 扫描一个目录下的多层文件夹中的py文件,并将结果写入html文件

假如我们有如下所示的一个目录结构需要进行扫描测试:

[dechin@dechin-manjaro bandit_test]$ tree
.
├── bad.py
├── bad.txt
├── level2
│   └── test_random.py
├── subprocess_Popen.py
├── test_bandit.html
└── test_bandit.txt

1 directory, 6 files
[dechin@dechin-manjaro bandit_test]$ cat level2/test_random.py 
# test_bandit.py

import random

a = random.random() 

我们可以在当前目录下执行如下指令:

[dechin@dechin-manjaro bandit_test]$ bandit -r . -f html -o test_bandit.html
[main]  INFO    profile include tests: None
[main]  INFO    profile exclude tests: None
[main]  INFO    cli include tests: None
[main]  INFO    cli exclude tests: None
[main]  INFO    running on Python 3.8.5
[html]  INFO    HTML output written to file: test_bandit.html 

这里我们得到的结果是一个test_bandit.html文件,文件内容如下图所示:

  1. 使用配置文件禁用部分Issue
    在执行目录下创建一个.bandit文件,作如下配置就可以避免对B404的审查:
[bandit]
skips: B404 

执行的扫描结果如下图所示,我们可以看到B404相关的Issue已经不在列表中了:

  1. py文件中直接逃避bandit审计
    在待扫描的py文件的对应风险函数后加上如下注释,即可在bandit审计过程中自动忽略:
# bad.py

from subprocess_Popen import subprocess as sb

sb.Popen('touch bad.txt', shell = 1) # nosec 

这里我们可以看到最终的审计结果中,B604也随之而不见了,如下图所示。从这个案例中我们也可以知悉,bandit并不是一个用来作安全防护的工具,仅仅是用来做比较初步的python代码安全函数使用规范的审查工作,而扫描出来的问题是否处理,其实最终还是取决于开发者自己。

bandit简单性能测试

众所周知python语言的性能是极其受限的,因此bandit的性能也有可能十分的低下,这里让我们来定量的测试一下bandit的性能到底在什么水准。首先我们创建一个10000行的py文件,内容全部为危险函数的使用:

# gen.py

import os

with open('test_bandit_power.py', 'w') as py_file:
    py_file.write('import subprocess as sb\n')
    for i in range(10000):
        py_file.write('sb.Popen(\'whoami\', shell = 1)\n') 

通过执行python3 gen.py就可以生成一个10000行的危险函数文件test_bandit_power.py,大约300KB的大小。此时我们针对这单个的文件进行bandit扫描测试,我们发现这个过程极为漫长,并且生成了大量的错误日志:

[dechin@dechin-manjaro bandit_test]$ time bandit test_bandit_power.py -f html -o test_power.html
[main]  INFO    profile include tests: None
[main]  INFO    profile exclude tests: None
[main]  INFO    cli include tests: None
[main]  INFO    cli exclude tests: None
[main]  INFO    running on Python 3.8.5
[node_visitor]  INFO    Unable to find qualified name for module: test_bandit_power.py
[html]  INFO    HTML output written to file: test_power.html

real    0m6.239s
user    0m6.082s
sys     0m0.150s 

我们可以简单估算,如果10000行的代码都需要6s的时间来进行扫描,那么对于比较大的项目的1000000+的代码的扫描时间,则有可能达到10min往上,这个时间虽然也不是特别长,但是对于大型的项目而言这绝对不是一个非常高效的选择。

总结概要

在一些对安全性要求较高的开发项目中,有可能会禁止使用危险函数,如subprocess等。而bandit的作用旨在通过对代码的扫描自动化的给出安全危险函数分析意见,至于是否采纳,还是以不同项目的管理者需求为准。同时经过我们的测试发现,bandit在实际使用场景下性能表现并不如意,因此在大型项目中我们并不推荐使用,如果一定要使用也可以考虑进行针对性的配置。

版权声明

本文首发链接为:https://www.cnblogs.com/dechinphy/p/bandit.html
作者ID:DechinPhy
更多原著文章请参考:https://www.cnblogs.com/dechinphy/

使用bandit对目标python代码进行安全函数扫描的更多相关文章

  1. Python 字符串去除空格的五种方法

    在处理Python代码字符串的时候,我们常会遇到要去除空格的情况,所以就总结了多种方法供大家参考。1、strip()方法去除字符串开头或者结尾的空格str = " Hello world "str.strip()输出:"Hello world"2、lstrip......

  2. Python 日志打印之logging.getLogger源码分析

    日志打印之logging.getLogger源码分析日志打印之logging.getLogger源码分析By:授客 QQ:1033553122 #实践环境WIN 10Python 3.6.5#函数说明logging.getLogger(name=None)getLogger函数位于logging/_......

  3. python基于opencv实现人脸识别

    将opencv中haarcascade_frontalface_default.xml文件下载到本地,我们调用它辅助进行人脸识别。识别图像中的人脸#coding:utf-8import cv2 as cv# 读取原始图像img = cv.imread('face.png')# 调用熟悉的人脸分类器 ......

  4. python 图像增强算法实现详解

    使用python编写了共六种图像增强算法:1)基于直方图均衡化2)基于拉普拉斯算子3)基于对数变换4)基于伽马变换5)限制对比度自适应直方图均衡化:CLAHE6)retinex-SSR7)retinex-MSR其中,6和7属于同一种下的变化。将每种方法编写成一个函数,封装,可以直接在主函数中调用。采......

  5. 解读Python的文件读写

    前言本文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理。PS:如有需要Python学习资料的小伙伴可以加下Python快乐交流群:11362015451.概述Python中内置了文件读写的功能核心:读写文件其实请求操作系统打开一个文件对象【文件描述符】......

  6. python 合并列表的八种方法

    Python 语言里有许多(而且是越来越多)的高级特性,是 Python 发烧友们非常喜欢的。在这些人的眼里,能够写出那些一般开发者看不懂的高级特性,就是高手,就是大神。但你要知道,在团队合作里,炫技是大忌。为什么这么说呢?我说下自己的看法:越简洁的代码,越清晰的逻辑,就越不容易出错;在团队合作中,......

  7. python for循环内输出和外输出方式

    通过for循环求和,结果发现输出完全不一样,一个循环是输出每一步的结果,另一个循环是输出最终一次的结果,今天终于弄懂了。如下所示:补充:python中for循环输出(index,value)的两种方法index索引value索引值方法一、利用enumerate()list1=['a','s','d'......

  8. python 基于opencv去除图片阴影

    一、前言如果你自己打印过东西,应该有过这种经历。如果用自己拍的图片,在手机上看感觉还是清晰可见,但是一打印出来就是漆黑一片。比如下面这两张图片:因为左边的图片有大片阴影,所以打印出来的图片不堪入目(因为打印要3毛钱,所以第二张图片只是我用程序模拟的效果)。那有什么办法可以解决吗?答案是肯定的,今天我......

  9. 解决python 读取npy文件太大不能完全显示的问题

    python读取npy文件时,太大不能完全显示,其解决方法当用python读取npy文件时,会遇到npy文件太大,用print函数打印时不能完全显示,如以下情况:解决办法添加一行代码:np.set_printoptions(threshold = 1e6),其中threshold表示输出数组的元素数......

  10. 爬虫-urllib3模块的使用

    urllib3是一个功能强大,对SAP健全的 HTTP客户端,许多Python生态系统已经使用了urllib3。一、安装sudo pips install urllib3二、创建PoolManager对象通过urllib3访问网页,首先需要构造一个PoolManager实例对象用于处理与线程池的连接......

随机推荐

  1. JavaScript—深入理解函数

    当程序在调用某个函数时,做了以下的工作:准备执行环境,初始函数作用域链和arguments参数对象。函数概述函数的声明语句function命令声明的代码区块,就是一个函数。function命令后面是函数名,函数名后面是一对圆括号,里面是传 入函数的参数。函数体放在大括号里面。function hel......

  2. Vue中引入svg图标的两种方式

    Vue中引入svg图标的方式Vue中引入svg图标的方式一安装yarn add svg-sprite-loader --devsvg组件index.vueexport default {name: 'SvgIcon',props: {// svg 的名称svgName: {type: String,......

  3. Python学习(3) (变量的基本使用、定义、类型、计算、类型转换、输入输出、命名)

    Python学习(3)一、python变量的定义二、pycharm单步执行查看变量值三、python变量的类型四、python变量间的计算五、python变量的输入输出1. input 函数用法2. 类型转换函数3. 变量的格式化输出六、python变量的命名1.标识符2.关键字3.变量的命名规则程......

  4. spring使用RedisTemplate操作Redis数据库

    一.什么是RedisRedis是一个非关系型数据库,具有很高的存取性能,一般用作缓存数据库,减少正常存储数据库的压力。Redis可以存储键与5种不同数据结构类型之间的映射,这5种数据结构类型分别为String(字符串)、List(列表)、Set(集合)、Hash(散列)和 Zset(有序集合)。下面......

  5. JS removeAttribute()方法实现删除元素的某个属性

    在 JavaScript 中,使用元素的 removeAttribute() 方法可以删除指定的属性。用法如下:removeAttribute(name)参数 name 表示元素的属性名。示例1下面示例演示了如何动态设置表格的边框。window.onload = function () { //绑定......

  6. Java使用Sftp和Ftp实现对文件的上传和下载

    sftp和ftp两种方式区别,还不清楚的,请自行百度查询,此处不多赘述。完整代码地址在结尾!!第一步,导入maven依赖<!-- FTP依赖包 --><dependency><groupId>commons-net</groupId><artif......

  7. 常见大中型网络WLAN基本业务实例

    组网图形大中型WLAN网络简介本文介绍的WLAN网络是指利用频率为2.4GHz或5GHz的射频信号作为传输介质的无线局域网,相对于有线网络的铺设成本高,不便于网络调整和扩展、位置固定,移动性差等缺点,WLAN网络以其低廉的铺设成本、便捷的网络调整和扩展、灵活的可移动性获得了越来越广泛的应用。组网需求......

  8. .NET的并发编程(TPL编程)是什么?

    写在前面优秀软件的一个关键特征就是具有并发性。过去的几十年,我们可以进行并发编程,但是难度很大。以前,并发性软件的编写、调试和维护都很难,这导致很多开发人员为图省事放弃了并发编程。新版 .NET 中的程序库和语言特征,已经让并发编程变得简单多了。随着 Visual Studio 2012 的发布,微......

  9. 理解C#中的 async await

    前言一个老掉牙的话题,园子里的相关优秀文章已经有很多了,我写这篇文章完全是想以自己的思维方式来谈一谈自己的理解。(PS:文中涉及到了大量反编译源码,需要静下心来细细品味)从简单开始为了更容易理解这个问题,我们举一个简单的例子:用异步的方式在控制台上分两步输出“Hello World!”,我这边使用的......

  10. 详解MySQL与Spring的自动提交(autocommit)

    1 MySQL的autocommit设置MySQL默认是开启自动提交的,即每一条DML(增删改)语句都会被作为一个单独的事务进行隐式提交。如果修改为关闭状态,则执行DML语句之后要手动提交 才能生效。查询当前会话的自动提交是否开启:mysql> show variables like 'aut......