最近文章

numpy.tile()扩展函数

理解tile的意思,就容易理解tile的用法:n.瓦片; (贴墙或铺地用的)瓷砖; 地砖; 小方地毯; 片状材料; (铺屋顶的)瓦; (棋盘游戏的)棋子;vt.铺瓦; 铺地砖; 贴瓷砖; 平铺显示; 瓦片式显示定义numpy.tile(A, reps)通过重复数组A来构造新的数组,从而达到扩展A的作用。重复次数有reps指定。tile原意是铺瓷砖,形象理解就把A作为瓷砖,平铺显示。参数A:arra
标签:

Python 3用PyPDF2给PDF添加文字(中文乱码处理)

有时我们需要向指定的pdf添加一些文字,在python 3.x 提供了PyPDF2和io.BytesIO,我们可以使用它们来完成次任务。环境准备1、安装PyPDF2pip install PyPDF22、安装和reportlabpip install reportlab Python3.x 示例from PyPDF2 import PdfFileWriter, PdfFileReader impo
标签:

Python替代三元表达式

在Python里时没有三元表达式:条件表达式?表达式1:表达式2但有一些替代方案:true返回的值 if 条件表达式 else false返回的值value_when_true if condition else value_when_false示例:'Yes' if fruit == 'Apple' else 'No'通过赋值的方式:fruit = 'Apple'isApple = True i
标签:

Python swith表达式替代方案

Python里是没有像其他语言,如java里的switch...case这样的表达式。替代方案一:map下标def f(x): return { 'a': 1, 'b': 2, }[x]使用下标的方式,可以很简洁的获取想要的值。但这种方法有一个弊端,如果不存在时,不能返回一个默认的值。替代方案:使用if-elifif x == 'a': # 满足条件,
标签:

RabbitMQ使用rabbitmqctl添加用户管理

rabbitmqctrl是RabbitMQ的管理工具,在RabbitMQ安装目录的sbin下。虚拟主机管理添加虚拟主机rabbitmqctl add_vhost <vhost> 删除虚拟主机rabbitmqctl delete_vhost <vhost>用户管理 添加用户rabbitmqctl add_user <username> <
标签:

[译]保护你的GraphQL API,以防恶意查询

Max Stoiber是Spectrum的在线社区实时聊天平台的首席技术官。 在这篇文章中,他描述了他们是如何在攻击中保护GraphQL API。使用GraphQL,你可以随时查询想要的内容。 这对于使用API来说是惊人的,但也具有复杂的安全隐患。 恶意攻击者可能会提交耗时的嵌套查询来超载你的服务器,数据库,网络或所有这些,而不是要求提供合法有用的
标签:

numpy.tile()扩展函数

发布于 2023.04.12 0分钟阅读 0 评论 5 推荐

    numpy

    作者: Csvion
  1. numpy.tile()扩展函数 Page 1

理解tile的意思,就容易理解tile的用法:

  • n.瓦片; (贴墙或铺地用的)瓷砖; 地砖; 小方地毯; 片状材料; (铺屋顶的)瓦; (棋盘游戏的)棋子;
  • vt.铺瓦; 铺地砖; 贴瓷砖; 平铺显示; 瓦片式显示

定义

numpy.tile(A, reps)

通过重复数组A来构造新的数组,从而达到扩展A的作用。重复次数有reps指定。tile原意是铺瓷砖,形象理解就把A作为瓷砖,平铺显示。

参数

  • A:array_like,输入数组。
  • reps:array_like,A沿各个轴的重复次数。
  • 返回值cndarray,扩展后的数组

假设reps长度为d,则新数组的扩展后的维度为max(d,A.ndim)。

示例

a = np.array([0, 1, 2])
>>> np.tile(a, 2)
array([0, 1, 2, 0, 1, 2])
>>> np.tile(a, (2, 2))
array([[0, 1, 2, 0, 1, 2],
       [0, 1, 2, 0, 1, 2]])
>>> np.tile(a, (2, 1, 2))
array([[[0, 1, 2, 0, 1, 2]],
       [[0, 1, 2, 0, 1, 2]]])
  • np.tile(a, 2)表示将数组a,在一维扩展2倍。
  • np.tile(a, (2,2))表示在将数组a,在一维数组扩展2倍,然后再二维数组扩展2倍。
  • np.tile(a, (2,1,2))表示在将数组a,在一维数组扩展2倍,在二维数组不扩展,最后在三维数组扩展2倍。
b = np.array([[1, 2], [3, 4]])
>>> np.tile(b, 2)
array([[1, 2, 1, 2],
       [3, 4, 3, 4]])
>>> np.tile(b, (2, 1))
array([[1, 2],
       [3, 4],
       [1, 2],
       [3, 4]])

 

 

 

Python 3用PyPDF2给PDF添加文字(中文乱码处理)

有时我们需要向指定的pdf添加一些文字,在python 3.x 提供了PyPDF2和io.BytesIO,我们可以使用它们来完成次任务。

环境准备

1、安装PyPDF2

pip install PyPDF2

2、安装和reportlab

pip install reportlab 

Python3.x 示例

from PyPDF2 import PdfFileWriter, PdfFileReader
import io
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
import sys

# 屏蔽警告
if not sys.warnoptions:
    import warnings
    warnings.simplefilter("ignore")

packet = io.BytesIO()
# 使用Reportlab创建一个新的PDF
can = canvas.Canvas(packet, pagesize=letter)
can.drawString(10, 100, "Hello world")
can.save()
# buffer从偏移0开始
packet.seek(0)
new_pdf = PdfFileReader(packet)
# 读取已有的PDF
existing_pdf = PdfFileReader(open("original.pdf", "rb"))
output = PdfFileWriter()
# 
page = existing_pdf.getPage(0)
page.mergePage(new_pdf.getPage(0))
output.addPage(page)
# 最后,向目标的pdf写出
outputStream = open("destination.pdf", "wb")
output.write(outputStream)
outputStream.close()

Python2.7示例

Python2.7可以使用pyPdf和StringIO来向指定的pdf添加一些文字。

from pyPdf import PdfFileWriter, PdfFileReader
import StringIO
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
packet = StringIO.StringIO()
# 使用Reportlab创建新的PDF
can = canvas.Canvas(packet, pagesize=letter)
can.drawString(10, 100, "Hello world")
can.save()
# StringIO buffer从偏移0开始
packet.seek(0)
new_pdf = PdfFileReader(packet)
# 读取已有的PDF
existing_pdf = PdfFileReader(file("original.pdf", "rb"))
output = PdfFileWriter()
# 
page = existing_pdf.getPage(0)
page.mergePage(new_pdf.getPage(0))
output.addPage(page)
# 最后,向目的pdf写出
outputStream = file("destination.pdf", "wb")
output.write(outputStream)
outputStream.close()

中文乱码

reporterlab默认是不支持中文的,如果想使用中文,需要自己安装注册中文字体。

例如SimSun.ttf是中文字体。把它下载然后放到site-packages/reportlab/fonts目录下,

from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
    
# 注册中文字体
pdfmetrics.registerFont(TTFont('SimSun', "SimSun.ttf"))

canvas调用设置字体:

canvas.setFont("SimSun",16)

Python3.x中文示例

# -*- coding:utf-8*-
from PyPDF2 import PdfFileWriter, PdfFileReader
import io
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
import sys

# 屏蔽警告
if not sys.warnoptions:
    import warnings
    warnings.simplefilter("ignore")

# 注册中文字体
pdfmetrics.registerFont(TTFont('SimSun', "SimSun.ttf"))

packet = io.BytesIO()
# 使用Reportlab创建一个新的PDF
can = canvas.Canvas(packet, pagesize=letter)
can.setFont("SimSun",14)
can.drawString(10, 100, "你好")
can.save()
# buffer从偏移0开始
packet.seek(0)
new_pdf = PdfFileReader(packet)
# 读取已有的PDF
existing_pdf = PdfFileReader(open("original.pdf", "rb"))
output = PdfFileWriter()
#
page = existing_pdf.getPage(0)
page.mergePage(new_pdf.getPage(0))
output.addPage(page)
# 最后,向目标的pdf写出
outputStream = open("destination.pdf", "wb")
output.write(outputStream)
outputStream.close()

Python替代三元表达式

在Python里时没有三元表达式:

条件表达式?表达式1:表达式2

但有一些替代方案:

true返回的值 if 条件表达式 else false返回的值
value_when_true if condition else value_when_false

示例:

'Yes' if fruit == 'Apple' else 'No'

通过赋值的方式:

fruit = 'Apple'
isApple = True if fruit == 'Apple' else False

这样非常简洁,可以对比下使用if语句:

fruit = 'Apple'
isApple = False
if fruit == 'Apple' : isApple = True

Python swith表达式替代方案

Python里是没有像其他语言,如java里的switch...case这样的表达式。

替代方案一:map下标

def f(x):
return {
'a': 1,
'b': 2,
}[x]

使用下标的方式,可以很简洁的获取想要的值。但这种方法有一个弊端,如果不存在时,不能返回一个默认的值。

替代方案:使用if-elif

if x == 'a':
# 满足条件,进行处理
elif x == 'b':
# 满足条件,进行处理
if x in 'bc':
# 满足条件,进行处理
elif x in 'xyz':
# 满足条件,进行处理
else:
# 默认


RabbitMQ使用rabbitmqctl添加用户管理

rabbitmqctrl是RabbitMQ的管理工具,在RabbitMQ安装目录的sbin下。

虚拟主机管理

添加虚拟主机

rabbitmqctl add_vhost <vhost> 

删除虚拟主机

rabbitmqctl delete_vhost <vhost>

用户管理 

添加用户

rabbitmqctl add_user <username> <password>    

设置用户标签

rabbitmqctl set_user_tags <username> <tag> ...    

用户标签类型包括:

  • management :访问 management plugin;
  • policymaker :访问 management plugin 和管理自己 vhosts 的策略和参数;
  • monitoring :访问 management plugin 和查看所有配置和通道以及节点信息;
  • administrator :一切权限;
  • None :无配置

设置用户权限

rabbitmqctl set_permissions [-p <vhost>] <user> <conf> <write> <read>    

示例:

rabbitmqctl add_vhost vh    
rabbitmqctl add_user test test
rabbitmqctl set_user_tags test management
rabbitmqctl set_permissions -p vh test ".*" ".*" ".*"   

[译]保护你的GraphQL API,以防恶意查询

Max Stoiber是Spectrum的在线社区实时聊天平台的首席技术官。 在这篇文章中,他描述了他们是如何在攻击中保护GraphQL API。

使用GraphQL,你可以随时查询想要的内容。 这对于使用API来说是惊人的,但也具有复杂的安全隐患。 恶意攻击者可能会提交耗时的嵌套查询来超载你的服务器,数据库,网络或所有这些,而不是要求提供合法有用的数据。 如果没有正确的保护措施,你就会面临DoS(拒绝服务)攻击。

例如,在Spectrum的GraphQL API中,我们有这样的关系:

type Thread {
  messages(first: Int, after: String): [Message]
}

type Message {
  thread: Thread
}

type Query {
  thread(id: ID!): Thread
}

如你所见,你可以查询主题的消息或消息的主题。 这个循环关系会让不怀好意的人构建一个费时的嵌套查询,如下所示:

query maliciousQuery {
  thread(id: "some-id") {
    messages(first: 99999) {
      thread {
        messages(first: 99999) {
          thread {
            messages(first: 99999) {
              thread {
                # ...repeat times 10000...
              }
            }
          }
        }
      }
    }
  }
}

让这种查询通过是非常糟糕,因为它会以指数方式增加所加载对象的数量,并且会使整个服务器崩溃。 虽然在其他应用层有一些缓解措施使在开始发送查询变得困难(如CORS),但它们无法完全防止发生。

大小限制

我们考虑的第一种天真的方法是通过原始字节来限制传入查询的大小。 由于查询是以字符串形式发送的,因此快速检查就足够了:

app.use('*', (req, res, next) => {
  const query = req.query.query || req.body.query || '';
  if (query.length > 2000) {
    throw new Error('Query too large');
  }
  next();
});

不幸的是,在实践中这样做效果并不佳:该检查可能会允许使用短字段名称进行讨厌的查询,或者使用长字段名称或嵌套片段来防止合法查询。

查询白名单

我们考虑的第二种方法是在我们自己的应用程序中使用已批准查询的白名单,告诉服务器除了名单里的查询外,禁止任何其他的查询。

app.use('/api', graphqlServer((req, res) => {
  const query = req.query.query || req.body.query;
  // TODO: Get whitelist somehow
  if (!whitelist[query]) {
    throw new Error('Query is not in whitelist.');
  }
  /* ... */
}));

手动维护已批准查询的列表显然是一件痛苦的事情,但幸运的是,Apollo团队创建了persistgraphql,它会自动从你的客户端代码中提取所有查询,并生成一个不错的JSON文件。

{
  "scripts": {
    "postbuild": "persistgraphql src api/query-whitelist.json"
  }
}

这项技术可以很好地工作,并可靠地阻止所有恶意查询。 不幸的是,它还有两个主要的折衷:

1、我们永远不能更改或删除查询,只能添加新的查询:如果任何用户运行过时的客户端,我们不能阻止他们的请求。 我们可能不得不保留所有在生产中使用的查询的历史,这是非常复杂的。

2、我们无法向公众开放我们的API:在未来的某个时候,我们希望向公众开放我们的API,以便其他开发人员可以构建他们对Spectrum界面外观的呈现。 如果我们只通过查询白名单,已经严重限制了他们的选择,并且破坏了拥有GraphQL API的重要性。

那些限制是我们无法使用的,所以我们得重新设计。

深度限制

上述恶意查询的一个有害方面是嵌套,按其深度分类,这使得查询成倍增加。 每层都会给后端增加更多的工作,当与列表结合使用时,增加的更快。

我们查找了一下,发现了graphql-depth-limit,这是Andrew Carlson写的一个可爱模块,它使我们能够轻松限制传入查询的最大深度。 我们检查了我们的客户端,我们使用的最深的查询有7个级别,所以我们使用了(相当宽松的)最大深度为10的值,并将其添加到我们的验证规则中:

app.use('/api', graphqlServer({
  validationRules: [depthLimit(10)]
}));

这就是简单的深度限制!

数量限制

上述查询的第二个有害方面是获取99999个对象。 无论这个对象是什么,取一吨它总是很耗时的。 (尽管DataLoader可能会缓解数据库压力,但网络和处理压力不会)

我们没有将第一个参数的类型设置为Int(允许任意数量),而是使用graphql-input-number创建了一个自定义标量,该标量将最大值限制为100:

const PaginationAmount = GraphQLInputInt({
  name: 'PaginationAmount',
  min: 1,
  max: 100,
});

如果任何人查询超过100个对象,这将抛出错误。 然后,我们可以在任何有连接的地方使用该API:

现在我们完全阻止了上面的恶意查询!

查询成本分析

不幸的是,在正确的条件下仍然有可能压倒服务器:有一些特定于应用程序的查询既不太深也不要求太多的对象,但仍然非常耗时。 对于我们Spectrum来说,这样的查询可能如下所示:

query evilQuery {
  thread(id: "54887141-57a9-4386-807c-ed950c4d5132") {
    messageConnection(first: 100) { ... }
    participants(first: 100) {
      threadConnection(first: 100) { ... }
      communityConnection { ... }
      channelConnection { ... }
      everything(first: 100) { ... }
    }
  }
}

在这个查询中,深度和个别金额都不是特别高,所以它会通过我们当前的保护。 然而,它可能会提取数以万计的记录,这意味着它在数据库,服务器和网络上是最为严重的情况,这是最糟糕的情况。

为了防止这种情况,我们需要分析查询,然后再运行它们来计算它们的复杂性,如果它们太耗时,则会阻止它。虽然这比我们以前的两项保护措施都要做得更好,但它可以确保没有恶意查询可以到达我们的解决方案。

在你要花大量时间实施查询成本分析之前,请确定你的确需要它。 尝试使用糟糕的查询来崩溃或放慢API,来检测它的承受能力 - 也许你的API是没有这些嵌套关系,或者它可以处理一次获取数千条记录,而且没有问题,这是不需要做查询成本分析的!

我在最新发布的2017年MacBook Pro上本地运行了上述查询,并且我们的API服务器花费了10-15秒的时间来响应1M字节的JSON。 我们真的需要它,因为我们永远不希望有人用我们的API来轰炸我们的API。 (The GitHub GraphQL API also uses Query Cost Analysis

实施查询成本分析

在npm上有几个包来实现查询成本分析。 前两名是graphql-validation-complexity,一个即插即用模块,或graphql-cost-analysis,它可以让你指定@cost指令,从而获得更多的控制。 还有graphql-query-complexity,但与graphql-cost-analysis相比,我是不推荐选择它的,因为它是没有指令或乘法支持。

我们使用graphql-cost-analysis进行分析,因为我们最快的解析器(20μs)和最慢的解析器(10s +)之间存在很大差异,所以我们需要从中获得控制。 也就是说,也许graphql-validation-complexity对你来说已经足够了,试试吧!

它的工作方式是指定解析特定字段或类型的相对成本。 它也有乘法支持,所以如果你要求列表中的任何嵌套字段将乘以分页数量,这是非常整洁。

这就是@cost指令在实践中的样子:

type Participant {
  # The complexity of getting one thread in a thread connection is 3, and multiply that by the amount of threads fetched
  threadConnection(first: PaginationAmount, after: String): ThreadConnection @cost(complexity: 3, multipliers: ["first"])
}

type Thread {
  author: Author @cost(complexity: 1)
  participants(first: PaginationAmount,...): [Participant] @cost(complexity: 2, multipliers: ["first"])
}

这只是我们API类型的代码片段,但你应该明白了。 你可以指定某个字段的复杂程度,乘以哪个参数以及最大成本,而graphql-cost-analysis会为你完成其余的工作。

我通过Apollo Engine公开的性能跟踪数据确定了某些解析器的复杂程度。 我看了整个模式,并根据p99服务时间分配了一个值。 然后,我们查看了我们客户的所有查询,找出最耗时的一个,其中有500点复杂度。 为了给我们一点未来的余地,我们将最大复杂度设置为750。

运行上面的evilQuery,现在我们添加了graphql-cost-analysis,我收到一条错误消息,告诉我“GraphQL查询超过最大复杂度,请删除一些嵌套或字段,然后重试。 (最大750,实际1010319)“

100万点复杂度? 拒绝!

总结

总而言之,我建议使用深度和数量限制作为任何GraphQL API的最低保护 - 它们很容易实现,并且会提供足够的安全性。 根据您的特定安全要求和架构,您可能还需要做查询成本分析。 虽然它比其他工具的工作多一点,但它确实提供了针对恶意行为者的全面覆盖。

原文:Securing Your GraphQL API from Malicious Queries