如何通过使用 "依赖注入 "来捕捉和修复Guice的问题?Sensei

出版日期:2021年1月25日
作者:Alan Richardson
案例研究

如何通过使用 "依赖注入 "来捕捉和修复Guice的问题?Sensei

出版日期:2021年1月25日
作者:Alan Richardson
查看资源
查看资源

Sensei 项目本身也有自己的一套配方,这些配方是随着时间的推移而建立起来的。这篇博文是Sensei 团队为其中一个场景建立配方的例子。Guice的一个错误配置,导致在测试中运行时报告NullPointerException。

这可以推广到许多依赖性注入的场景,即代码在语法上是正确的,但由于布线配置不正确,错误就会溜走。

这经常发生在我们学习技术的时候,我们总是犯一些简单的错误,忘记把东西连起来。但这种情况也发生在有经验的专业人士身上,因为......我们都会犯错,而且我们可能没有单元测试来覆盖所有的东西。

 

不正确的依赖性注入接线产生的运行时间异常

下面的代码在运行时以NullPointerException失败。

injector = Guice.createInjector(new SystemOutModule());
CountReporter reporter = injector.getInstance(CountReporter.class);
String [] lines5 = {"1: line", "2: line", "3: line", "4: line", "5: line"};
reporter.reportThisMany(Arrays.asList(lines5));
Assertions.assertEquals(5, reporter.getCount());


这段代码在语法上是正确的,但由于我们在SystemOutModule配置中漏掉了一个requestStaticInjection,所以失败了。

public class SystemOutModule extends AbstractModule {
    @Override
    protected void configure() {
        binder().bind(ILineReporter.class).to(SystemOutReporter.class);
    }
}


当我们试图使用使用Injector创建的报告器时,它没有被完全实例化,当我们调用reportThisMany时,我们收到一个NullPointerException。

我们很可能在代码审查中漏掉了这一点,或者我们没有触发依赖注入的单元测试,而使它在我们的构建中溜走了。

警告信号

在这种情况下,有一个警告信号,CountReporter有一个用@Inject注解的静态字段,但是......CountReporter类本身是封装私有的。

在一个复杂的代码库中,这可能是一个警告信号,表明代码是不正确的,因为配置绑定的模块类需要在同一个包中才能工作。

class CountReporter {
    @Inject
    private static ILineReporter reporter;


我们犯的另一个错误是,我们可能在代码审查中发现,我们忘记了在SystemOutModule配置方法中实际绑定字段。

binder().requestStaticInjection(CountReporter.class)。


如果我们写了requestStaticInjection代码,那么在试图使用CountReporter时产生的语法错误会提醒我们注意这个简单的错误。

> 'reporters.CountReporter'在'reporters'中不公开。不能从包外访问

遗憾的是。我们忘记了,代码中没有句法上的警告标志。

Sensei 能提供什么帮助?

我们可能不会使用Sensei 来拾取缺少的requestStaticInjection,因为我们所有的Guice配置布线都需要使用该方法,而且我们不能保证所有的布线都会像这个用例一样简单。

我们可以写一个Sensei 规则来寻找一些警告信号,说明我们的代码不合格。

在这种情况下,这将意味着。

  • 找到任何带有@Inject注解字段的类
  • 凡是不公开的课程。

上述情况是警告信号,他们不太可能是被布线了。

通过创建一个配方,那么我们就可以在编码过程中及早得到一个警告信号,并减少对我们的拉动请求或解决我们的技术债务的依赖,以使我们能够添加单元测试。

如何创建一个食谱?

我想完成的任务是。

  • 创建一个配方,匹配在受保护的私有类中用@Inject注释的字段。

这应该能给我们足够的警告,以确定任何使用它的模块,并添加缺少的接线代码。

在我的CountReporter类中,我将使用Alt+Enter来创建一个新的配方,我将从零开始

我将为其命名并添加描述。

名字。Guice:Injected Field Not Public
说明。如果Injected字段不是公开的,那么代码可能没有被连接起来
Level。警告


我写的搜索是寻找一个有注解为Inject的字段的类,但它的范围没有被定为public。

search:
field:
with:
annotation:
type:"com.google.inject.Inject"
in:
class:
without:
modifier:"公共"

修复

配方中的QuickFix将通过改变范围来修正注入的类。但这并不是我必须要改变的唯一代码。

可用的修复方法。

- name: "Change class to public.记住也要请求对这个类进行注入"
actions:
- changeModifiers:
visibility:"public"
target: "parentClass"
Sensei 编辑配方QuickFix设置

当配方被触发时,我仍然有一个手动步骤要在我的代码中执行,添加包含requestStaticInjection的行来完全实例化对象。

public class SystemOutModule extends AbstractModule {
    @Override
    protected void configure() {
        binder().bind(ILineReporter.class).to(SystemOutReporter.class);
        // instantiate via dependency injection
        binder().requestStaticInjection(CountReporter.class);
    }
}


我有可能再写一个配方来接上这个。我可能不会这样做,除非忘记添加静态注入成为我在编码时犯的一个半常规错误。

摘要

如果我们发现自己犯了一个常见的根基模式的错误,那么Sensei ,可以帮助编纂围绕检测和修复问题的知识,然后希望它不会通过代码审查和进入生产。

有时,我们编写的配方会识别出启发式模式,即与之匹配并不能保证有问题,但很可能有问题。

此外,我们编写的食谱和快速修复方法不一定要完全全面,它们需要足够好,以帮助我们识别和修复问题,而不会过于复杂。因为当它们变得过于复杂时,就会变得更难理解,更难维护。

---


你可以使用 "Preferences \ Plugins"(Mac)或 "Settings \ Plugins"(Windows)从IntelliJ内部安装Sensei ,然后只要搜索 "sensei secure code"。


这篇文章的源代码和配方可以在Secure Code Warrior GitHub账户的`sensei-blog-examples`仓库中的`guiceexamples`模块中找到。


https://github.com/securecodewarrior/sensei-blog-examples

了解更多关于Sensei



查看资源
查看资源

作者

艾伦-理查德森

想要更多吗?

在博客上深入了解我们最新的安全编码见解。

我们广泛的资源库旨在增强人类对安全编码技术提升的方法。

查看博客
想要更多吗?

获取关于开发者驱动的安全的最新研究

我们广泛的资源库充满了有用的资源,从白皮书到网络研讨会,让你开始使用开发者驱动的安全编码。现在就去探索它。

资源中心

如何通过使用 "依赖注入 "来捕捉和修复Guice的问题?Sensei

出版日期:2021年1月25日
作者:Alan Richardson

Sensei 项目本身也有自己的一套配方,这些配方是随着时间的推移而建立起来的。这篇博文是Sensei 团队为其中一个场景建立配方的例子。Guice的一个错误配置,导致在测试中运行时报告NullPointerException。

这可以推广到许多依赖性注入的场景,即代码在语法上是正确的,但由于布线配置不正确,错误就会溜走。

这经常发生在我们学习技术的时候,我们总是犯一些简单的错误,忘记把东西连起来。但这种情况也发生在有经验的专业人士身上,因为......我们都会犯错,而且我们可能没有单元测试来覆盖所有的东西。

 

不正确的依赖性注入接线产生的运行时间异常

下面的代码在运行时以NullPointerException失败。

injector = Guice.createInjector(new SystemOutModule());
CountReporter reporter = injector.getInstance(CountReporter.class);
String [] lines5 = {"1: line", "2: line", "3: line", "4: line", "5: line"};
reporter.reportThisMany(Arrays.asList(lines5));
Assertions.assertEquals(5, reporter.getCount());


这段代码在语法上是正确的,但由于我们在SystemOutModule配置中漏掉了一个requestStaticInjection,所以失败了。

public class SystemOutModule extends AbstractModule {
    @Override
    protected void configure() {
        binder().bind(ILineReporter.class).to(SystemOutReporter.class);
    }
}


当我们试图使用使用Injector创建的报告器时,它没有被完全实例化,当我们调用reportThisMany时,我们收到一个NullPointerException。

我们很可能在代码审查中漏掉了这一点,或者我们没有触发依赖注入的单元测试,而使它在我们的构建中溜走了。

警告信号

在这种情况下,有一个警告信号,CountReporter有一个用@Inject注解的静态字段,但是......CountReporter类本身是封装私有的。

在一个复杂的代码库中,这可能是一个警告信号,表明代码是不正确的,因为配置绑定的模块类需要在同一个包中才能工作。

class CountReporter {
    @Inject
    private static ILineReporter reporter;


我们犯的另一个错误是,我们可能在代码审查中发现,我们忘记了在SystemOutModule配置方法中实际绑定字段。

binder().requestStaticInjection(CountReporter.class)。


如果我们写了requestStaticInjection代码,那么在试图使用CountReporter时产生的语法错误会提醒我们注意这个简单的错误。

> 'reporters.CountReporter'在'reporters'中不公开。不能从包外访问

遗憾的是。我们忘记了,代码中没有句法上的警告标志。

Sensei 能提供什么帮助?

我们可能不会使用Sensei 来拾取缺少的requestStaticInjection,因为我们所有的Guice配置布线都需要使用该方法,而且我们不能保证所有的布线都会像这个用例一样简单。

我们可以写一个Sensei 规则来寻找一些警告信号,说明我们的代码不合格。

在这种情况下,这将意味着。

  • 找到任何带有@Inject注解字段的类
  • 凡是不公开的课程。

上述情况是警告信号,他们不太可能是被布线了。

通过创建一个配方,那么我们就可以在编码过程中及早得到一个警告信号,并减少对我们的拉动请求或解决我们的技术债务的依赖,以使我们能够添加单元测试。

如何创建一个食谱?

我想完成的任务是。

  • 创建一个配方,匹配在受保护的私有类中用@Inject注释的字段。

这应该能给我们足够的警告,以确定任何使用它的模块,并添加缺少的接线代码。

在我的CountReporter类中,我将使用Alt+Enter来创建一个新的配方,我将从零开始

我将为其命名并添加描述。

名字。Guice:Injected Field Not Public
说明。如果Injected字段不是公开的,那么代码可能没有被连接起来
Level。警告


我写的搜索是寻找一个有注解为Inject的字段的类,但它的范围没有被定为public。

search:
field:
with:
annotation:
type:"com.google.inject.Inject"
in:
class:
without:
modifier:"公共"

修复

配方中的QuickFix将通过改变范围来修正注入的类。但这并不是我必须要改变的唯一代码。

可用的修复方法。

- name: "Change class to public.记住也要请求对这个类进行注入"
actions:
- changeModifiers:
visibility:"public"
target: "parentClass"
Sensei 编辑配方QuickFix设置

当配方被触发时,我仍然有一个手动步骤要在我的代码中执行,添加包含requestStaticInjection的行来完全实例化对象。

public class SystemOutModule extends AbstractModule {
    @Override
    protected void configure() {
        binder().bind(ILineReporter.class).to(SystemOutReporter.class);
        // instantiate via dependency injection
        binder().requestStaticInjection(CountReporter.class);
    }
}


我有可能再写一个配方来接上这个。我可能不会这样做,除非忘记添加静态注入成为我在编码时犯的一个半常规错误。

摘要

如果我们发现自己犯了一个常见的根基模式的错误,那么Sensei ,可以帮助编纂围绕检测和修复问题的知识,然后希望它不会通过代码审查和进入生产。

有时,我们编写的配方会识别出启发式模式,即与之匹配并不能保证有问题,但很可能有问题。

此外,我们编写的食谱和快速修复方法不一定要完全全面,它们需要足够好,以帮助我们识别和修复问题,而不会过于复杂。因为当它们变得过于复杂时,就会变得更难理解,更难维护。

---


你可以使用 "Preferences \ Plugins"(Mac)或 "Settings \ Plugins"(Windows)从IntelliJ内部安装Sensei ,然后只要搜索 "sensei secure code"。


这篇文章的源代码和配方可以在Secure Code Warrior GitHub账户的`sensei-blog-examples`仓库中的`guiceexamples`模块中找到。


https://github.com/securecodewarrior/sensei-blog-examples

了解更多关于Sensei



我们希望得到您的许可,向您发送有关我们产品和/或相关安全编码主题的信息。我们将始终以最谨慎的态度对待您的个人资料,绝不会将其出售给其他公司用于营销目的。

提交
要提交表格,请启用 "分析 "cookies。完成后,请随时再次禁用它们。