SQL 解析在 CloudQuery 中的应用

Posted CloudQuery

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL 解析在 CloudQuery 中的应用相关的知识,希望对你有一定的参考价值。

hi 好久不见!今天将为大家带来一期干货满满的技术分享。

作为一款数据库管控平台,大家通常认为 CloudQuery 的核心能力是对平台的管控,包括统一入口管理、权限体系、审计分析等,但实际上 CloudQuery 的核心技术点之一在于其独特的 SQL 解析能力。

01

SQL 解析功能界定

SQL 解析是指将结构化查询语言( SQL 语句)转换成可以被数据库系统理解和执行的内部表示形式的过程。在执行 SQL 查询之前,数据库系统需要对查询语句进行解析,以确定查询语句的语法是否正确,是否存在语义错误,并生成执行计划。

目前 SQL 解析工具有 Druid、JSqlParser、Apache Calcite、Presto 等,它们都提供了一些 API 用于分析 SQL 语句中的信息,比如获取表名、列名等字段。但是上述工具提供的 SQL 解析功能通常封装性比较强,扩展性不足,支持的数据源有限,在许多特殊场景下它们无法准确的给出 SQL 解析结果。

因此, CloudQuery 技术团队选择使用 ANTLR 作为 SQL 解析的引擎。ANTLR 作为 SQL 解析引擎具有很多优势,它帮助我们构建高效、可扩展和易于维护的 SQL 解析器。

02

SQL 解析原理介绍

SQL 解析是将用户输入的 SQL 语句转换为数据库能够理解的结构化查询语言的过程,与普通编程语言的解析无本质区别。主要分为词法分析、语法分析、语义分析、优化、代码生成这些步骤。SQL 解析的原理可以分为两个主要阶段:词法分析和语法分析。

词法分析

词法分析是将 SQL 语句分解为一个个单独的 Token,标识每一个关键字、符号或者其他语法元素的过程。词法分析器会逐个读取 SQL 语句中的字符,根据预定义好的规则组成不同的 Token,并将 Token 序列传递给下一个步骤。

比如,下面是一个简单的 SELECT 语句:

SELECT FirstName FROM Employee WHERE Department = \'Sales\'

在进行词法分析后,将生成的 Token 序列如下:

图片

语法分析

语法分析是将 Token 序列转换成语法分析树,并进行语义分析、类型检查等处理的过程。语法分析器会根据事先定义好的 SQL 语法规则,将 Token 序列转换为语法分析树,并对其进行分析,以确定 SQL 语句是否符合语法规范。

比如,针对上述 SELECT 语句,语法分析器会将其转换为以下语法分析树:

SELECT_STATEMENT
/ | \\
SELECT COLUMN_LIST FROM WHERE
| | |
FirstName Employee Department = \'Sales\'

SQL 语句数据收集

在经过词法分析和语法分析的步骤后,我们就得到了一棵语法分析树。我们要收集 SQL 语句中的表名、列名、表达式等信息,其实就是遍历这个语法树的各个节点,将想要获取的信息保存下来。

在上面的语法树中,我们通过访问 COLUMN_LIST 节点可以获取到语句中查询的列名,通过 FROM 节点可以获取到语句中查询的表名,通过WHERE 节点可以获取到语句中的查询条件。

有了这些信息,我们就可以基于这些信息做许多数据库方面的功能,比如 SQL 语句权限管控、SQL 合法性检查、SQL 高危操作检查等。

03

SQL 解析在 CloudQuery 中的应用

CloudQuery 很多功能的实现都离不开强大的 SQL 解析能力,SQL 解析是 CQ 稳步前行的一大基石。

SQL 高亮

在编辑框中输入一条 SQL 语句,可以看到语句中的关键字部分 SELECT、FROM、WHERE 会被渲染成蓝色,这其实就是上面讲到的词法分析的应用。

图片

在语句经过词法分析后,语句会变成一系列 Token,Token 代表了语句中不同类型的字符。Token 大致上可以分为关键字、标识符、数字、字符串、注释这几种,然后编辑器就可以根据这几种类别,将用户输入的 SQL 语句进行着色。

语法提示

我们在输入 SQL 的过程中,比如输入下面的文本:

SELECT * FROM SYS.

通常输入到这里的时候,我们希望提示出 SYS 下面的一些信息来帮助我们快速写完 SQL,比如提示出表名、视图名、函数名等。目前 CloudQuery 在用户书写 SQL 语句的过程中有完善的智能提示功能, 包括提示出关键字、表名、列名、函数名、子查询别名等。

这里 SQL 的智能提示技术就是上面讲到的语法分析的应用,当我们输入 SELECT FROM SYS. 的时候,其实已经经过语法分析构成了一棵语法树,只是这棵语法树不完整,CloudQuery 在用户输入 SQL 语句时会实时遍历语法树,找出当前语法树中缺失的节点,在例子中缺失的节点就是表名节点,由此可以得到我们当前提示信息应该是 SYS 下的表名或视图名。

图片

SQL 语句权限控制

CloudQuery 使用基于角色的权限访问控制体系,权限控制粒度可以详细到每一种 SQL 语句、每一个数据库对象。比如常用的 SELECT、UPDATE、DELETE、CREATE TABLE、CREATE FUNCTION、函数调用等语句。

这里语句权限的控制就是 SQL 解析的重要应用场景,CloudQuery 在接收到用户输入的 SQL 语句后,会经过上述的词法分析和语法分析步骤,再遍历语法树收集 SQL 语句中的信息。在信息收集过程中,会提取出 SQL 语句中涉及到的所有表名、列名、别名、函数、查询条件等信息,接下来会对这些信息做进一步加工处理,比如消除 TABLE 的别名、绑定列的来源表、对象的真实类型查询等。

无权限的用户输入下面的SQL语句,将会受到权限管控:

SELECT * FROM "SYS"."ACCESS$" LEFT JOIN "SYS"."ACLMV$";
DELETE FROM "CQ"."USER" WHERE ID = 1;
CREATE OR REPLACE FUNCTION GET_UUID RETURN VARCHAR2 IS
uuid VARCHAR2(32);
BEGIN
uuid := REPLACE(SYS_GUID(),\'-\',\'\');
RETURN uuid;
END;
BEGIN
"CQ"."GET_UUID"();
END;

图片

动态过滤数据行

CloudQuery 支持数据行安全控制,行安全控制是 CloudQuery 的一项安全特性,它允许管理员定义基于行的安全规则,以限制用户在表中的访问权限。

使用行安全控制,可以根据用户的角色、组织、部门等信息来动态控制数据的可见性,从而增强数据库的安全性。CloudQuery 的行安全控制条件支持任意的 SQL 表达式、支持引用用户的任何参数值、支持引用系统级别的参数值、支持引用环境变量等。

下面用一个例子说明行安全控制的使用场景: 存在一张业务数据表,其中有一个部门字段( dept ),管理员希望普通用户在查询这张表里的数据时,只能查询到自己部门的数据。在 CloudQuery 可以通过给表配置行安全控制实现上面的需求,配置方式类似下面这样:

DEPT = \'$USER.DEPT\'

上面配置中 DEPT 是表中的列名, $USER.DEPT 是引用用户的部门参数,在真正执行 SQL 时这里会被替换成用户的真实部门值。用户在执行下面的 SQL 语句时:

SELECT * FROM DEPT;

最终执行的 SQL 会被修改成:

SELECT * FROM DEPT WHERE DEPT = \'dept1\';

行安全控制的实现方式也依赖于 SQL 解析,在经过前面所说的词法分析、语法分析、SQL 语句信息收集这几步后,我们可以收集到语句中的需要行过滤的表名,当然还要知道这个表名所在的 SELECT 语句的位置信息, 以及所在 SELECT 语句中 FROM 的位置和WHERE条件的位置。通过这些信息,我们就可以对原始语句进行改写。

以上就是 SQL 解析在 CloudQuery 中的基本应用,正是凭借强大的 SQL 解析能力,CloudQuery 持续不断地为用户提供稳定高效的操作体验。

图片

CloudQuery 安全系列: Http 与 Https

随着当前大数据时代数据量激增,各种应用互联互通上云后Web安全也成了近几年关注的热点,各种扫描、渗透测试、检测围绕在各个web应用周围,随着云趋势的流行网络层的安全保障就显得格外重要。

CloudQuery作为一款基于Web的数据管控工具,安全一直是CloudQuery关注的重点。所以我们就此开了一个关于CloudQuery Web安全的专题来给大家详细介绍我们是如何搭建自己的安全体系的。

But!我们的产品经理说这个系列更新完全看她心情,如果大家反响热烈的话她还能开一个「DTS」系列——是的,CloudQuery要出DTS了!大家有任何想法可以去官网底部找她的邮箱反馈哈哈!

好的,言归正传,本文我们就开启CloudQuery安全系列第一篇,详细介绍Http和Https两大协议。

Http是什么?

我们都知道Http是当前应用最广泛的网络协议,基于它简捷、快速的特性迅速在互联网应用中推广开来。一个Http请求是由一个请求行、多个请求报头,最后跟随一个空的文本行来终止报头列表组成的。同时随着协议的不断发展,目前已经支持到GET、POST、OPTIONS、HEAD、PUT、DELETE、TRACE请求方式,但由于研究调查发现99%的Http请求都是GET类型,所以本文接下来会针对广为应用的GET方法进行重点探讨。Http带来的便利性是毋庸置疑的,有了Http后,用户可以利用一个浏览器来访问不同的应用系统,脱离桌面端限制后用户操作的便利性得到了大幅提升。

Http协议的主要特点可以概括如下:

  • 协议简单。整个链路可以概括为:“ 客户端发起请求 ->服务端响应请求 -> 重新发起新请求 ” ,每一次请求都是独立的行为,这也体现了Http无状态的特点。
  • 只需浏览器。Http协议完美支持B/S架构,只要有浏览器就可以工作,用户操作简便。甚至从某种意义上说,APP也可以当作某种特定内容的浏览器。
  • 灵活性好。无论是数据传输、视频播放都可以灵活使用。非常适合快速迭代的互联网Web应用。

Http的缺陷分析

总结了Http协议的特点后不难发现,Http是未经过任何加密处理的。通过简单的网络抓包就可以获得请求包中的所有内容,再对包中的内容进行分析就可以得到用户的访问行为。从交互角度来分析,Http作为Web应用的基础协议,其特点就是用户请求->服务器响应,在整个过程中服务器始终处于被动响应状态,不会主动获取用户信息。在这种信息交换的环境下,客户端可以随意篡改请求内容,而服务端却必须对客户端提交的请求进行响应,这也就是Http最核心的问题:

  • 信息未加密,链路中容易被获取或截断、劫持
  • 请求易被模仿、篡改

Https及其认证方式详解

上文中提到了Http的种种缺点,而Https就是为了解决这三大风险而设计的,从严格意义上来说, Https并不是一个独立的协议,而是工作在SSL协议上的Http协议。
在这里插入图片描述
SSL是一种为网络通信提供安全以及数据完整性的安全协议,这也是有效保障用户数据安全的措施。而Https的认证流程根据认证次数可以分为单向认证和双向认证。

单向认证的特点在于只有客户端对服务端进行身份验证,服务端只对提交的加密密钥进行识别处理,并不会对客户端的合法性进行验证,这就存在会受到SSL剥离攻击的隐患,例如SSL Strip工具的原理就是劫持用户的请求,并模拟用户来与目标站点建立Https连接,成功连接后利用已经建立的连接的对称密钥解密服务器返回的Https,将其中的Http再发回客户端。这是由于单向认证中服务器并不对客户端的有效性进行检查造成的。

而双向认证主要是增加了服务器对客户端的合法性校验,这样就可以有效避免刚才提到的SSL剥离攻击。客户端发起的请求中会包含SSL参数,从服务端获取证书,再将该证书提交给CA,CA验证该证书的合法性后通知客户端,客户端根据CA的验证结果来确认目标站点的真实性。此处与单向认证存在两处不同:

  • 服务端要求客户端的请求中携带证书并接受用户的公钥
  • 客户端与服务端互相利用对方的公钥加密来协商可支持的传输类型和密码方案。

客户端从服务端的返回中得到公钥后再利用公钥对自身产生的密钥进行对称加密,再将加密后的密文发送至服务端;服务端利用私钥解密得到数据后进行系统内部业务逻辑处理。

CloudQuery配置Https

CloudQuery平台支持用户便捷、快速接入Https,部署后默认使用Http协议,需要切换Https协议时只需用户布置一个支持Https协议的反向代理服务器即可。接入Https后CloudQuery前端会自动发起Https或wss请求。本章将以教程的形式带领各位配置Https,该配置教程使用本地的证书和域名,实际证书请使用自己申请的证书和域名。

实现方式如下图,nginx Https 代理服务器需要用户自行添加配置。
在这里插入图片描述

  • 生成证书(如果已经申请到证书可跳过本步)
sudo mkdir /tmp/ssl
# 创建了有效期100年,加密强度为RSA2048的SSL密钥key和X509证书文件。
sudo openssl req -x509 -nodes -days 36500 -newkey rsa:2048 -keyout /tmp/ssl/nginx.key -out /tmp/ssl/nginx.crt
# 执行上面的命令后,需要在Common Name选项中填入域名,示例使用 *.cqcommunity.club
  • 创建 nginx 配置文件
touch /tmp/ssl/nginx.conf
  • 编辑 /tmp/nginx.conf 文件内容(请将#注释中的替换为实际配置)
worker_processes 1;
events{
worker_connections 1024;
}
http{
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
gzip on;
gzip_min_length 1k;
gzip_comp_level 5;
gzip_types text/plain application/javascript application/x-javascript test/javascript text/css text/xml;
gzip_disable "MSIE [1-6]\\.";
gzip_vary on;
server {
        listen       80;
        server_name  www.cqcommunity.club;
        rewrite ^ https://$http_host$request_uri? permanent;    # force redirect http to https
    #return 301 https://$http_host$request_uri;
    }


server {
        listen 443 ssl;
    charset utf-8;
    ssl_certificate /etc/nginx/ssl/nginx.crt; # 这里填自己的证书
    ssl_certificate_key /etc/nginx/ssl/nginx.key; # 这里填自己的证书
    keepalive_timeout   70;
    server_name www.cqcommunity.club;  # 这里填自己的域名
    server_tokens off;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
    access_log      /var/log/nginx/wiki.xby1993.net.access.log;
    error_log       /var/log/nginx/wiki.xby1993.net.error.log;
    location / {
                proxy_set_header Host $host;
                proxy_set_header Cookie $http_cookie;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_pass http://172.17.0.1:9898;  #这里的地址通过容器访问宿主机的ip ,9898是cloudquery使用的端口
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection "upgrade";
        }
    }
 include servers/*;
}
  • 启动&配置 nginx 镜像
# 下载 nginx 镜像
docker pull nginx
# 启动 nginx 并监听 80 和 443 端口
docker run --name cloudquery_https_nginx -p 80:80 -p 443:443 -d nginx
# 容器内部创建文件夹,用来存放证书文件
docker exec -t cloudquery_https_nginx sh -c 'mkdir /etc/nginx/ssl'
# 将刚才生成的证书文件复制到容器内部
docker cp /tmp/ssl/nginx.key cloudquery_https_nginx:/etc/nginx/ssl/
docker cp /tmp/ssl/nginx.crt cloudquery_https_nginx:/etc/nginx/ssl/
docker cp /tmp/ssl/nginx.conf cloudquery_https_nginx:/etc/nginx/ssl/
# 重启容器
docker restart cloudquery_https_nginx
  • 修改客户端 hosts
# 如果你使用的备案过的域名,则不必添加这个配置
sudo sh -c "echo '${ip} www.cqcommunity.club' >> /etc/hosts"

至此配置完毕,请尝试浏览器访问 https://www.cqcommunity.club/login 页面。请求结构如图:
在这里插入图片描述
从图中我们不难看出部署反向代理器后由客户端(浏览器)在外网环境发起Https请求时会先请求至反向代理服务器,再由该代理服务器转发至内网环境,内网环境下一般不存在请求伪造以及劫持情况,此时以Http协议再向CloudQuery所在服务器进行会话请求。Https方式不仅提高了外网环境下的会话安全性,保证用户数据安全想的同时也在一定程度上保护了服务端,让恶意攻击和伪装数据的成本大大提高。

至此就是本文对Http和Https的介绍,以及Https在CloudQuery中的应用。可以看出,Https重点解决的是传输过程中的安全问题,可以用来保障客户端的传输数据安全,虽然并不会直接提升Web站点的安全性,但在一定程度上解决了传输过程中的截断、泄漏等问题。

下一篇我们从XSS攻击的角度来进行注入攻击的防护,有缘再见。

官网地址:https://cloudquery.club/
在这里插入图片描述

以上是关于SQL 解析在 CloudQuery 中的应用的主要内容,如果未能解决你的问题,请参考以下文章

CloudQuery 安全系列: Http 与 Https

CloudQuery 安全系列: Http 与 Https

CloudQuery 如何实现云上数据导入导出

CloudQuery 如何实现云上数据导入导出

CloudQuery 如何实现云上数据导入导出

CloudQuery 社区重启 | 愿归来仍是少年