private TimeSpan DefaultTimeout { get; } = new TimeSpan(0, 0, 0, 0, 500); // FUTURE use configuration value public LoginAttemptController( LoginAttemptClient loginAttemptClient, UserAccountClient userAccountClient, MemoryUsageLimiter memoryUsageLimiter, BlockingAlgorithmOptions blockingOptions, IStableStore stableStore) { _options = blockingOptions;//optionsAccessor.Options; _stableStore = stableStore; _passwordPopularityTracker = new PasswordPopularityTracker("FIXME-uniquekeyfromconfig" //FIXME -- use configuration to get options here"FIXME-uniquekeyfromconfig", thresholdRequiredToTrackPreciseOccurrences: 10); ); _loginAttemptCache = new FixedSizeLruCache<string, LoginAttempt>(80000); // FIXME -- use configuration file for size _loginAttemptsInProgress = new Dictionary<string, Task<LoginAttempt>>(); _ipHistoryCache = new SelfLoadingCache<IPAddress, IpHistory>( (id, cancellationToken) => { return Task.Run(() => new IpHistory(id), cancellationToken); // FUTURE -- option to load from stable store }); _loginAttemptClient = loginAttemptClient; _loginAttemptClient.SetLocalLoginAttemptController(this); SetUserAccountClient(userAccountClient); memoryUsageLimiter.OnReduceMemoryUsageEventHandler += ReduceMemoryUsage; }
// This method gets called by a runtime. // Use this method to add services to the container public void ConfigureServices(IServiceCollection services) { // Add Application Insights data collection services to the services container. services.AddApplicationInsightsTelemetry(Configuration); services.AddMvc(); // Uncomment the following line to add Web API services which makes it easier to port Web API 2 controllers. // You will also need to add the Microsoft.AspNet.Mvc.WebApiCompatShim package to the 'dependencies' section of project.json. // services.AddWebApiConventions(); var hosts = new MaxWeightHashing<RemoteHost>("FIXME-uniquekeyfromconfig"); RemoteHost localHost = new RemoteHost {Uri = new Uri("http://localhost:35358")}; services.AddSingleton<RemoteHost>(x => localHost); hosts.Add("localhost", localHost); // Use memory only stable store if none other is available. FUTURE -- use azure SQL or tables services.AddSingleton<IStableStore, MemoryOnlyStableStore>(); var options = new BlockingAlgorithmOptions(); services.AddSingleton<BlockingAlgorithmOptions>(x => options); services.AddSingleton<BlockingAlgorithmOptions>(x => options); services.AddSingleton<MemoryUsageLimiter, MemoryUsageLimiter>(); services.AddSingleton<IDistributedResponsibilitySet<RemoteHost>>(x => hosts); services.AddSingleton<UserAccountClient>(); services.AddSingleton<LoginAttemptClient>(); services.AddSingleton<UserAccountController>(); services.AddSingleton<LoginAttemptController>(); }
public IpHistory( IPAddress address, BlockingAlgorithmOptions options) { Address = address; CurrentBlockScore = new DecayingDouble(); RecentPotentialTypos = new SmallCapacityConstrainedSet<LoginAttemptSummaryForTypoAnalysis>(options.NumberOfFailuresToTrackForGoingBackInTimeToIdentifyTypos); }
public IpHistory( IPAddress address, BlockingAlgorithmOptions options) { Address = address; CurrentBlockScore = new DecayingDouble(); RecentPotentialTypos = new SmallCapacityConstrainedSet <LoginAttemptSummaryForTypoAnalysis>(options.NumberOfFailuresToTrackForGoingBackInTimeToIdentifyTypos); }
public void Init() { var builder = new ConfigurationBuilder() .SetBasePath("") .AddJsonFile("appsettings.json"); builder.AddEnvironmentVariables(); Configuration = builder.Build(); sqlConnectionString = Configuration["Data:ConnectionString"]; string cloudStorageConnectionString = Configuration["Data:StorageConnectionString"]; _options = new BlockingAlgorithmOptions(); DbContextOptionsBuilder<DbUserAccountContext> dbOptionsBuilder = new DbContextOptionsBuilder<DbUserAccountContext>(); dbOptionsBuilder.UseSqlServer(sqlConnectionString); dbOptions = dbOptionsBuilder.Options; _CloudStorageAccount = CloudStorageAccount.Parse(cloudStorageConnectionString); userAccountControllerFactory = new DbUserAccountControllerFactory(_CloudStorageAccount, dbOptions); userAccountController = userAccountControllerFactory.CreateDbUserAccountController(); RemoteHost localHost = new RemoteHost { Uri = new Uri("http://localhost:35358") }; MaxWeightHashing<RemoteHost> hosts = new MaxWeightHashing<RemoteHost>(Configuration["Data:UniqueConfigurationSecretPhrase"]); LoginAttemptClient<DbUserAccount> loginAttemptClient = new LoginAttemptClient<DbUserAccount>(hosts, localHost); _UserAccountRepositoryFactory = new DbUserAccountRepositoryFactory(dbOptions); BinomialLadderFilter localPasswordBinomialLadderFilter = new BinomialLadderFilter( _options.NumberOfBitsInBinomialLadderFilter_N, _options.HeightOfBinomialLadder_H); _loginAttemptController = new LoginAttemptController<DbUserAccount>( userAccountControllerFactory, _UserAccountRepositoryFactory, localPasswordBinomialLadderFilter, new MemoryUsageLimiter(), _options); //services.AddEntityFramework() // .AddSqlServer() // .AddDbContext<DbUserAccountContext>(opt => opt.UseSqlServer(sqlConnectionString)); //DbUserAccountContext context = new DbUserAccountContext(); //var db = new DbContextOptionsBuilder(); //db.UseInMemoryDatabase(); //_context = new MyContext(db.Options); }
public UserAccountController( UserAccountClient userAccountClient, LoginAttemptClient loginAttemptClient, MemoryUsageLimiter memoryUsageLimiter, BlockingAlgorithmOptions options, IStableStore stableStore, LimitPerTimePeriod[] creditLimits) { // _options = optionsAccessor.Options; _options = options; _stableStore = stableStore; _userAccountClient = userAccountClient; CreditLimits = creditLimits; _userAccountCache = new SelfLoadingCache<string, UserAccount>(_stableStore.ReadAccountAsync); SetLoginAttemptClient(loginAttemptClient); userAccountClient.SetLocalUserAccountController(this); memoryUsageLimiter.OnReduceMemoryUsageEventHandler += ReduceMemoryUsage; }
public static TestConfiguration InitTest(BlockingAlgorithmOptions options = default(BlockingAlgorithmOptions)) { if (options == null) options = new BlockingAlgorithmOptions(); TestConfiguration configuration = new TestConfiguration(); configuration.MyBlockingAlgorithmOptions = options ?? new BlockingAlgorithmOptions(); //configuration.MyResponsibleHosts = new MaxWeightHashing<RemoteHost>("FIXME-uniquekeyfromconfig"); //RemoteHost localHost = new RemoteHost { Uri = new Uri("http://localhost:80") }; //configuration.MyResponsibleHosts.Add("localhost", localHost); //IStableStore stableStore = configuration.StableStore = new MemoryOnlyStableStore(); //configuration.MyLoginAttemptClient = new LoginAttemptClient(configuration.MyResponsibleHosts, localHost); MemoryUsageLimiter memoryUsageLimiter = new MemoryUsageLimiter(); BinomialLadderFilter localPasswordBinomialLadderFilter = new BinomialLadderFilter(options.NumberOfBitsInBinomialLadderFilter_N, options.HeightOfBinomialLadder_H); //MultiperiodFrequencyTracker<string> localPasswordFrequencyTracker = // new MultiperiodFrequencyTracker<string>( // options.NumberOfPopularityMeasurementPeriods, // options.LengthOfShortestPopularityMeasurementPeriod, // options.FactorOfGrowthBetweenPopularityMeasurementPeriods); configuration.MyAccountFactory = new MemoryOnlyUserAccountFactory(); configuration.MemUserAccountController = new MemoryUserAccountController(); LoginAttemptController<MemoryUserAccount> myLoginAttemptController = new LoginAttemptController<MemoryUserAccount>( new MemoryUserAccountControllerFactory(), configuration.MyAccountFactory, localPasswordBinomialLadderFilter, memoryUsageLimiter, configuration.MyBlockingAlgorithmOptions); configuration.MyLoginAttemptClient = myLoginAttemptController; //configuration.MyLoginAttemptClient.SetLocalLoginAttemptController(myLoginAttemptController); return configuration; }
public Simulator(ExperimentalConfiguration myExperimentalConfiguration, BlockingAlgorithmOptions options = default(BlockingAlgorithmOptions)) { MyExperimentalConfiguration = myExperimentalConfiguration; if (options == null) options = new BlockingAlgorithmOptions(); CreditLimits = new[] { // 3 per hour new LimitPerTimePeriod(new TimeSpan(1, 0, 0), 3f), // 6 per day (24 hours, not calendar day) new LimitPerTimePeriod(new TimeSpan(1, 0, 0, 0), 6f), // 10 per week new LimitPerTimePeriod(new TimeSpan(6, 0, 0, 0), 10f), // 15 per month new LimitPerTimePeriod(new TimeSpan(30, 0, 0, 0), 15f) }; //We are testing with local server now MyResponsibleHosts = new MaxWeightHashing<RemoteHost>("FIXME-uniquekeyfromconfig"); //configuration.MyResponsibleHosts.Add("localhost", new RemoteHost { Uri = new Uri("http://localhost:80"), IsLocalHost = true }); RemoteHost localHost = new RemoteHost { Uri = new Uri("http://localhost:80") }; MyResponsibleHosts.Add("localhost", localHost); MyUserAccountClient = new UserAccountClient(MyResponsibleHosts, localHost); MyLoginAttemptClient = new LoginAttemptClient(MyResponsibleHosts, localHost); MemoryUsageLimiter memoryUsageLimiter = new MemoryUsageLimiter(); MyUserAccountController = new UserAccountController(MyUserAccountClient, MyLoginAttemptClient, memoryUsageLimiter, options, StableStore, CreditLimits); MyLoginAttemptController = new LoginAttemptController(MyLoginAttemptClient, MyUserAccountClient, memoryUsageLimiter, options, StableStore); MyUserAccountController.SetLoginAttemptClient(MyLoginAttemptClient); MyUserAccountClient.SetLocalUserAccountController(MyUserAccountController); MyLoginAttemptController.SetUserAccountClient(MyUserAccountClient); MyLoginAttemptClient.SetLocalLoginAttemptController(MyLoginAttemptController); //fix outofmemory bug by setting the loginattempt field to null StableStore.LoginAttempts = null; }
public static TestConfiguration InitTest(BlockingAlgorithmOptions options = default(BlockingAlgorithmOptions)) { TestConfiguration configuration = new TestConfiguration(); if (options == null) options = new BlockingAlgorithmOptions(); configuration.CreditLimits = new[] { // 3 per hour new LimitPerTimePeriod(new TimeSpan(1, 0, 0), 3f), // 6 per day (24 hours, not calendar day) new LimitPerTimePeriod(new TimeSpan(1, 0, 0, 0), 6f), // 10 per week new LimitPerTimePeriod(new TimeSpan(6, 0, 0, 0), 10f), // 15 per month new LimitPerTimePeriod(new TimeSpan(30, 0, 0, 0), 15f) }; configuration.MyResponsibleHosts = new MaxWeightHashing<RemoteHost>("FIXME-uniquekeyfromconfig"); RemoteHost localHost = new RemoteHost { Uri = new Uri("http://localhost:80") }; configuration.MyResponsibleHosts.Add("localhost", localHost); IStableStore stableStore = configuration.StableStore = new MemoryOnlyStableStore(); configuration.MyUserAccountClient = new UserAccountClient(configuration.MyResponsibleHosts, localHost); configuration.MyLoginAttemptClient = new LoginAttemptClient(configuration.MyResponsibleHosts, localHost); MemoryUsageLimiter memoryUsageLimiter = new MemoryUsageLimiter(); configuration.MyUserAccountController = new UserAccountController(configuration.MyUserAccountClient, configuration.MyLoginAttemptClient, memoryUsageLimiter, options, stableStore, configuration.CreditLimits); LoginAttemptController myLoginAttemptController = new LoginAttemptController(configuration.MyLoginAttemptClient, configuration.MyUserAccountClient, memoryUsageLimiter, options, stableStore); configuration.MyUserAccountController.SetLoginAttemptClient(configuration.MyLoginAttemptClient); configuration.MyUserAccountClient.SetLocalUserAccountController(configuration.MyUserAccountController); myLoginAttemptController.SetUserAccountClient(configuration.MyUserAccountClient); configuration.MyLoginAttemptClient.SetLocalLoginAttemptController(myLoginAttemptController); return configuration; }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddMvc(); string sqlConnectionString = Configuration["Data:ConnectionString"]; services.AddDbContext<DbUserAccountContext>( opt => opt.UseSqlServer(sqlConnectionString)); // Uncomment the following line to add Web API services which makes it easier to port Web API 2 controllers. // You will also need to add the Microsoft.AspNet.Mvc.WebApiCompatShim package to the 'dependencies' section of project.json. // services.AddWebApiConventions(); BlockingAlgorithmOptions options = new BlockingAlgorithmOptions(); services.AddSingleton<BlockingAlgorithmOptions>(x => options); RemoteHost localHost = new RemoteHost { Uri = new Uri("http://localhost:35358") }; services.AddSingleton<RemoteHost>(x => localHost); MaxWeightHashing<RemoteHost> hosts = new MaxWeightHashing<RemoteHost>(Configuration["Data:UniqueConfigurationSecretPhrase"]); hosts.Add("localhost", localHost); services.AddSingleton<IDistributedResponsibilitySet<RemoteHost>>(x => hosts); string cloudStorageConnectionString = Configuration["Data:StorageConnectionString"]; CloudStorageAccount cloudStorageAccount = CloudStorageAccount.Parse(cloudStorageConnectionString); services.AddSingleton<CloudStorageAccount>(a => cloudStorageAccount); services.AddSingleton<MemoryUsageLimiter, MemoryUsageLimiter>(); if (hosts.Count > 0) { DistributedBinomialLadderFilterClient dblfClient = new DistributedBinomialLadderFilterClient( options.NumberOfVirtualNodesForDistributedBinomialLadder, options.HeightOfBinomialLadder_H, hosts, options.PrivateConfigurationKey, options.MinimumBinomialLadderFilterCacheFreshness); // If running as a distributed system services.AddSingleton<IBinomialLadderFilter, DistributedBinomialLadderFilterClient>(x => dblfClient); DistributedBinomialLadderFilterController filterController = new DistributedBinomialLadderFilterController(dblfClient, options.NumberOfBitsPerShardInBinomialLadderFilter, options.PrivateConfigurationKey); services.AddSingleton<DistributedBinomialLadderFilterController>(x => filterController); //services.AddSingleton<IFrequenciesProvider<string>>(x => // new IncorrectPasswordFrequencyClient(hosts, options.NumberOfRedundantHostsToCachePasswordPopularity)); } else { BinomialLadderFilter localPasswordBinomialLadderFilter = new BinomialLadderFilter(options.NumberOfBitsInBinomialLadderFilter_N, options.HeightOfBinomialLadder_H); services.AddSingleton<IBinomialLadderFilter>(x => localPasswordBinomialLadderFilter); } LoginAttemptClient<DbUserAccount> loginAttemptClient = new LoginAttemptClient<DbUserAccount>(hosts, localHost); services.AddSingleton<IUserAccountRepositoryFactory<DbUserAccount>, DbUserAccountRepositoryFactory>(); services.AddSingleton<IUserAccountControllerFactory<DbUserAccount>, DbUserAccountControllerFactory>(); //LoginAttemptController<DbUserAccount> loginAttemptController = new LoginAttemptController<DbUserAccount>( // new DbUserAccountControllerFactory(cloudStorageAccount), new DbUserAccountRepositoryFactory()); services.AddSingleton<ILoginAttemptClient, LoginAttemptClient<DbUserAccount>>(i => loginAttemptClient); services.AddSingleton<ILoginAttemptController, LoginAttemptController<DbUserAccount>>(); }
public async Task Main(string[] args) { //for (int i = 1; i < 10; i++) //{ // ExperimentalConfiguration expConfig1 = new ExperimentalConfiguration(); // BlockingAlgorithmOptions blockConfig1 = new BlockingAlgorithmOptions(); // blockConfig1.FOR_SIMULATION_ONLY_TURN_ON_SSH_STUPID_MODE = true; // //blockConfig1.BlockThresholdUnpopularPassword = 1 * i; // //blockConfig1.BlockThresholdPopularPassword = blockConfig1.BlockThresholdUnpopularPassword; // // // // Industrial-best-practice baseline // // // // Use the same threshold regardless of the popularity of the account password // blockConfig1.BlockThresholdPopularPassword = // blockConfig1.BlockThresholdUnpopularPassword =1*i; // // Make all failures increase the count towards the threshold by one // blockConfig1.PenaltyForInvalidAccount = // blockConfig1.PenaltyMulitiplierForTypo = // blockConfig1.BasePenaltyForInvalidPassword = // 1d; // // If the below is empty, the multiplier for any popularity level will be 1. // blockConfig1.PenaltyForReachingEachPopularityThreshold = new List<PenaltyForReachingAPopularityThreshold>(); // // Correct passwords shouldn't help // blockConfig1.RewardForCorrectPasswordPerAccount = 0; // // // expConfig1.TotalLoginAttemptsToIssue = 5000; // expConfig1.RecordUnitAttempts = 5000; // //expConfig1.ChanceOfBenignPasswordTypo = 0.2d; // Simulator simulator = new Simulator(expConfig1, blockConfig1); // Console.WriteLine("Unpopularpassword {0}", blockConfig1.BlockThresholdUnpopularPassword); // // await simulator.Run(blockConfig1); //} ulong TotalLoginAttemptsToIssue = 200000; ulong RecordUnitAttempts = 200000; uint MaliciousIP = 2000; //1. Vary BlockThresholdUnpopularPassword from 100 to 2100 (in steps of 200) for (int i = 0; i < 11; i++) { ExperimentalConfiguration expConfig1 = new ExperimentalConfiguration(); BlockingAlgorithmOptions blockConfig1 = new BlockingAlgorithmOptions(); //blockConfig1.RewardForCorrectPasswordPerAccount = -10 * i - 10; //blockConfig1.PenaltyForInvalidAccount = 1 + (int)(i/3); //blockConfig1.BlockThresholdPopularPassword = 20 + 10 * i; //blockConfig1.BlockThresholdUnpopularPassword = 4*blockConfig1.BlockThresholdPopularPassword; blockConfig1.BlockThresholdUnpopularPassword = 100 + 200 * i; expConfig1.TotalLoginAttemptsToIssue = TotalLoginAttemptsToIssue; expConfig1.RecordUnitAttempts = RecordUnitAttempts; expConfig1.NumberOfIpAddressesControlledByAttacker = MaliciousIP; //blockConfig1.BlockThresholdPopularPassword = 60; //blockConfig1.BlockThresholdUnpopularPassword = 900; //blockConfig1.PenaltyForInvalidAccount = 35; //blockConfig1.PenaltyForReachingEachPopularityThreshold = new List<PenaltyForReachingAPopularityThreshold> //{ // new PenaltyForReachingAPopularityThreshold { PopularityThreshold = 1d/(100*1000d), Penalty = 10*Math.Pow(2,0.3*i)}, // new PenaltyForReachingAPopularityThreshold { PopularityThreshold = 1d/(10*1000d), Penalty = 20*Math.Pow(2,0.3*i)}, // new PenaltyForReachingAPopularityThreshold { PopularityThreshold = 1d/(1*1000d), Penalty = 25*Math.Pow(2,0.3*i)}, // new PenaltyForReachingAPopularityThreshold { PopularityThreshold = 1d/(100d), Penalty = 30*Math.Pow(2,0.3*i)}, //}; Simulator simulator = new Simulator(expConfig1, blockConfig1); Console.WriteLine("unpopularpassword {0}", blockConfig1.BlockThresholdUnpopularPassword); await simulator.Run(blockConfig1, "BlockThresholdUnpopularPassword"); } //2. Vary blockthresholdpopularpassword from 20 - 120 and unpopularpassword is 4 times for (int i = 0; i < 10; i++) { ExperimentalConfiguration expConfig1 = new ExperimentalConfiguration(); BlockingAlgorithmOptions blockConfig1 = new BlockingAlgorithmOptions(); //blockConfig1.RewardForCorrectPasswordPerAccount = -10 * i - 10; //blockConfig1.PenaltyForInvalidAccount = 1 + (int)(i/3); blockConfig1.BlockThresholdPopularPassword = 20 + 10 * i; blockConfig1.BlockThresholdUnpopularPassword = 4 * blockConfig1.BlockThresholdPopularPassword; //blockConfig1.BlockThresholdUnpopularPassword = 100 + 200 * i; expConfig1.TotalLoginAttemptsToIssue = TotalLoginAttemptsToIssue; expConfig1.RecordUnitAttempts = RecordUnitAttempts; expConfig1.NumberOfIpAddressesControlledByAttacker = 100; //blockConfig1.BlockThresholdPopularPassword = 60; //blockConfig1.BlockThresholdUnpopularPassword = 900; //blockConfig1.PenaltyForInvalidAccount = 35; //blockConfig1.PenaltyForReachingEachPopularityThreshold = new List<PenaltyForReachingAPopularityThreshold> //{ // new PenaltyForReachingAPopularityThreshold { PopularityThreshold = 1d/(100*1000d), Penalty = 10*Math.Pow(2,0.3*i)}, // new PenaltyForReachingAPopularityThreshold { PopularityThreshold = 1d/(10*1000d), Penalty = 20*Math.Pow(2,0.3*i)}, // new PenaltyForReachingAPopularityThreshold { PopularityThreshold = 1d/(1*1000d), Penalty = 25*Math.Pow(2,0.3*i)}, // new PenaltyForReachingAPopularityThreshold { PopularityThreshold = 1d/(100d), Penalty = 30*Math.Pow(2,0.3*i)}, //}; Simulator simulator = new Simulator(expConfig1, blockConfig1); Console.WriteLine("Popularpassword {0}", blockConfig1.BlockThresholdPopularPassword); await simulator.Run(blockConfig1, "BlockThresholdPopularPassword"); } //3.Vary PenaltyForInvalidAccount from 1 to 10 (in steps of 1) for (int i = 0; i < 10; i++) { ExperimentalConfiguration expConfig1 = new ExperimentalConfiguration(); BlockingAlgorithmOptions blockConfig1 = new BlockingAlgorithmOptions(); //blockConfig1.RewardForCorrectPasswordPerAccount = -10 * i - 10; blockConfig1.PenaltyForInvalidAccount = 1 + i; //blockConfig1.BlockThresholdPopularPassword = 20 + 10 * i; //blockConfig1.BlockThresholdUnpopularPassword = 4 * blockConfig1.BlockThresholdPopularPassword; //blockConfig1.BlockThresholdUnpopularPassword = 100 + 200 * i; expConfig1.TotalLoginAttemptsToIssue = TotalLoginAttemptsToIssue; expConfig1.RecordUnitAttempts = RecordUnitAttempts; expConfig1.NumberOfIpAddressesControlledByAttacker = MaliciousIP; //blockConfig1.BlockThresholdPopularPassword = 60; //blockConfig1.BlockThresholdUnpopularPassword = 900; //blockConfig1.PenaltyForInvalidAccount = 35; //blockConfig1.PenaltyForReachingEachPopularityThreshold = new List<PenaltyForReachingAPopularityThreshold> //{ // new PenaltyForReachingAPopularityThreshold { PopularityThreshold = 1d/(100*1000d), Penalty = 10*Math.Pow(2,0.3*i)}, // new PenaltyForReachingAPopularityThreshold { PopularityThreshold = 1d/(10*1000d), Penalty = 20*Math.Pow(2,0.3*i)}, // new PenaltyForReachingAPopularityThreshold { PopularityThreshold = 1d/(1*1000d), Penalty = 25*Math.Pow(2,0.3*i)}, // new PenaltyForReachingAPopularityThreshold { PopularityThreshold = 1d/(100d), Penalty = 30*Math.Pow(2,0.3*i)}, //}; Simulator simulator = new Simulator(expConfig1, blockConfig1); Console.WriteLine("PenaltyForInvalidAccount {0}", blockConfig1.PenaltyForInvalidAccount); await simulator.Run(blockConfig1, "PenaltyForInvalidAccount"); } //4.Vary RewardForCorrectPasswordPerAccount from -10 to -100 for (int i = 0; i < 10; i++) { ExperimentalConfiguration expConfig1 = new ExperimentalConfiguration(); BlockingAlgorithmOptions blockConfig1 = new BlockingAlgorithmOptions(); blockConfig1.RewardForCorrectPasswordPerAccount = -10 * i - 10; //blockConfig1.PenaltyForInvalidAccount = 1 + (int)(i/3); // blockConfig1.BlockThresholdPopularPassword = 20 + 10 * i; //blockConfig1.BlockThresholdUnpopularPassword = 4 * blockConfig1.BlockThresholdPopularPassword; //blockConfig1.BlockThresholdUnpopularPassword = 100 + 200 * i; expConfig1.TotalLoginAttemptsToIssue = TotalLoginAttemptsToIssue; expConfig1.RecordUnitAttempts = RecordUnitAttempts; expConfig1.NumberOfIpAddressesControlledByAttacker = MaliciousIP; //blockConfig1.BlockThresholdPopularPassword = 60; //blockConfig1.BlockThresholdUnpopularPassword = 900; //blockConfig1.PenaltyForInvalidAccount = 35; //blockConfig1.PenaltyForReachingEachPopularityThreshold = new List<PenaltyForReachingAPopularityThreshold> //{ // new PenaltyForReachingAPopularityThreshold { PopularityThreshold = 1d/(100*1000d), Penalty = 10*Math.Pow(2,0.3*i)}, // new PenaltyForReachingAPopularityThreshold { PopularityThreshold = 1d/(10*1000d), Penalty = 20*Math.Pow(2,0.3*i)}, // new PenaltyForReachingAPopularityThreshold { PopularityThreshold = 1d/(1*1000d), Penalty = 25*Math.Pow(2,0.3*i)}, // new PenaltyForReachingAPopularityThreshold { PopularityThreshold = 1d/(100d), Penalty = 30*Math.Pow(2,0.3*i)}, //}; Simulator simulator = new Simulator(expConfig1, blockConfig1); Console.WriteLine("RewardForCorrectPasswordPerAccount {0}", blockConfig1.RewardForCorrectPasswordPerAccount); await simulator.Run(blockConfig1, "RewardForCorrectPasswordPerAccount"); } //5.PenaltyForReachingEachPopularityThreshold multiply each by 2 ^{ 0.3 * k} k0-10 for (int i = 0; i < 11; i++) { ExperimentalConfiguration expConfig1 = new ExperimentalConfiguration(); BlockingAlgorithmOptions blockConfig1 = new BlockingAlgorithmOptions(); //blockConfig1.RewardForCorrectPasswordPerAccount = -10 * i - 10; //blockConfig1.PenaltyForInvalidAccount = 1 + (int)(i/3); // blockConfig1.BlockThresholdPopularPassword = 20 + 10 * i; //blockConfig1.BlockThresholdUnpopularPassword = 4 * blockConfig1.BlockThresholdPopularPassword; //blockConfig1.BlockThresholdUnpopularPassword = 100 + 200 * i; expConfig1.TotalLoginAttemptsToIssue = TotalLoginAttemptsToIssue; expConfig1.RecordUnitAttempts = RecordUnitAttempts; expConfig1.NumberOfIpAddressesControlledByAttacker = MaliciousIP; //blockConfig1.BlockThresholdPopularPassword = 60; //blockConfig1.BlockThresholdUnpopularPassword = 900; //blockConfig1.PenaltyForInvalidAccount = 35; blockConfig1.PenaltyForReachingEachPopularityThreshold = new List<PenaltyForReachingAPopularityThreshold> { new PenaltyForReachingAPopularityThreshold { PopularityThreshold = 1d/(100*1000d), Penalty = 10*Math.Pow(2,0.3*i)}, new PenaltyForReachingAPopularityThreshold { PopularityThreshold = 1d/(10*1000d), Penalty = 20*Math.Pow(2,0.3*i)}, new PenaltyForReachingAPopularityThreshold { PopularityThreshold = 1d/(1*1000d), Penalty = 25*Math.Pow(2,0.3*i)}, new PenaltyForReachingAPopularityThreshold { PopularityThreshold = 1d/(100d), Penalty = 30*Math.Pow(2,0.3*i)}, }; Simulator simulator = new Simulator(expConfig1, blockConfig1); Console.WriteLine("PenaltyForReachingEachPopularityThreshold{0}", blockConfig1.PenaltyForReachingEachPopularityThreshold); await simulator.Run(blockConfig1, "PenaltyForReachingEachPopularityThreshold"); } //ExperimentalConfiguration expConfig = new ExperimentalConfiguration(); //BlockingAlgorithmOptions blockConfig = new BlockingAlgorithmOptions(); //Simulator simulator = new Simulator(expConfig, blockConfig); //await simulator.Run(); }
public async Task TestAccountingForTypoDetection() { BlockingAlgorithmOptions options = new BlockingAlgorithmOptions { BasePenaltyForInvalidPassword = 1, BlockThresholdPopularPassword = 1, BlockThresholdUnpopularPassword = 1, PenaltyMulitiplierForTypo = .25d }; // // Configure so that a single login attempt with an incorrect password // login will block future logins with correct passwords... unless // the incorrect login was the result of a typo. // TestConfiguration configuration = InitTest(options); const string userName = "******"; await CreateTestAccountAsync(configuration, userName, "IRunESPStudies"); // First, make sure we are correctly blocking when the failed login is not a typo. // Login attempt with incorrect password that is not a typo LoginAttempt attempt = await AuthenticateAsync(configuration, userName, "AndNowForAPasswordThat'sCompletelyDifferent", clientAddress: AttackersIp); Assert.Equal(AuthenticationOutcome.CredentialsInvalidIncorrectPassword, attempt.Outcome); // Login attempt that should be blocked attempt = await AuthenticateAsync(configuration, userName, "IRunESPStudies", clientAddress: AttackersIp); Assert.Equal(AuthenticationOutcome.CredentialsValidButBlocked, attempt.Outcome); // With another IP, lgoin with an incorrect password that IS a typo attempt = await AuthenticateAsync(configuration, userName, "IRunEPSStudies", clientAddress: ClientsIp); Assert.Equal(AuthenticationOutcome.CredentialsInvalidIncorrectPassword, attempt.Outcome); // Login attempt should be allowed through once typo is accounted for. attempt = await AuthenticateAsync(configuration, userName, "IRunESPStudies", clientAddress: ClientsIp); Assert.Equal(AuthenticationOutcome.CredentialsValid, attempt.Outcome); }
/// <summary> /// Evaluate the accuracy of our stopguessing service by sending user logins and malicious traffic /// </summary> /// <returns></returns> public async Task Run(BlockingAlgorithmOptions options, string ParameterSweep, CancellationToken cancellationToken = default(CancellationToken)) { //1.Create account from Rockyou //Create 2*accountnumber accounts, first half is benign accounts, and second half is correct accounts owned by attackers //Record the accounts into stable store try { GenerateSimulatedAccounts(); List<SimulatedAccount> allAccounts = new List<SimulatedAccount>(BenignAccounts); allAccounts.AddRange(MaliciousAccounts); Parallel.ForEach(allAccounts, async simAccount => { UserAccount account = UserAccount.Create(simAccount.UniqueId, (int)CreditLimits.Last().Limit, simAccount.Password, "PBKDF2_SHA256", 1); foreach (string cookie in simAccount.Cookies) account.HashesOfDeviceCookiesThatHaveSuccessfullyLoggedIntoThisAccount.Add(LoginAttempt.HashCookie(cookie)); await MyUserAccountController.PutAsync(account, cancellationToken: cancellationToken); }); } catch (Exception e) { using (StreamWriter file = new StreamWriter(@"account_error.txt")) { file.WriteLine("{0} Exception caught in account creation.", e); file.WriteLine("time is {0}", DateTime.Now.ToString(CultureInfo.InvariantCulture)); // file.WriteLine("How many requests? {0}", i); } } //using (StreamWriter file = new StreamWriter(@"account.txt")) //{ // file.WriteLine("time is {0}", DateTime.Now.ToString(CultureInfo.InvariantCulture)); // file.WriteLine("How many requests? {0}", i); //} Stopwatch sw = new Stopwatch(); sw.Start(); Stats stats = new Stats(); //ulong maliciouscount = 0; //ulong benigncount = 0; double falsePositiveRate = 0; double falseNegativeRate = 0; //The percentage of malicious attempts get caught (over all malicious attempts) double detectionRate = 0; //The percentage of benign attempts get labeled as malicious (over all benign attempts) double falseDetectionRate = 0; // List<int> Runtime = new List<int>(new int[MyExperimentalConfiguration.TotalLoginAttemptsToIssue]); for (int bigi = 0; bigi < (int)(MyExperimentalConfiguration.TotalLoginAttemptsToIssue / MyExperimentalConfiguration.RecordUnitAttempts); bigi++) { await TaskParalllel.ParallelRepeat(MyExperimentalConfiguration.RecordUnitAttempts, async () => { SimulatedLoginAttempt simAttempt; if (StrongRandomNumberGenerator.GetFraction() < MyExperimentalConfiguration.FractionOfLoginAttemptsFromAttacker) { simAttempt = MaliciousLoginAttemptBreadthFirst(); } else { simAttempt = BenignLoginAttempt(); } LoginAttempt attemptWithOutcome = await MyLoginAttemptController.LocalPutAsync(simAttempt.Attempt, simAttempt.Password);//, // cancellationToken: cancellationToken); AuthenticationOutcome outcome = attemptWithOutcome.Outcome; lock (stats) { stats.TotalLoopIterationsThatShouldHaveRecordedStats++; if (stats.TruePositives == 1) { stats.bootstrapsuccess = stats.FalseNegatives; stats.bootstrapall = stats.MaliciousCount; } if (simAttempt.IsGuess) { stats.MaliciousCount++; if (outcome == AuthenticationOutcome.CredentialsValidButBlocked) stats.TruePositives++; else if (outcome == AuthenticationOutcome.CredentialsValid) stats.FalseNegatives++; else stats.GuessWasWrong++; } else { stats.BenignCount++; if (outcome == AuthenticationOutcome.CredentialsValid) stats.TrueNegatives++; else if (outcome == AuthenticationOutcome.CredentialsValidButBlocked) stats.FalsePositives++; else stats.BenignErrors++; } } }, (e) => { lock (stats) { stats.TotalExceptions++; } Console.Error.WriteLine(e.ToString()); //count++; }); if (((double)stats.FalsePositives + stats.TruePositives) != 0) { falsePositiveRate = ((double)stats.FalsePositives) / ((double)stats.FalsePositives + stats.TruePositives); } if (((double)stats.FalseNegatives + stats.TrueNegatives) != 0) falseNegativeRate = ((double)stats.FalseNegatives) / ((double)stats.FalseNegatives + stats.TrueNegatives); if (((double)stats.TruePositives + stats.FalseNegatives) != 0) detectionRate = ((double)stats.TruePositives) / ((double)stats.TruePositives + stats.FalseNegatives); if (((double)stats.FalsePositives + stats.TrueNegatives) != 0) falseDetectionRate = ((double)stats.FalsePositives) / ((double)stats.FalsePositives + stats.TrueNegatives); //using (StringWriter filename = new StringWriter()) //{ // filename.Write("Detailed_PenaltyForReachingAPopularityThreshold{0}.txt", options.PenaltyForReachingEachPopularityThreshold[0]); // //string filename = "Detailed_Log_Unpopular{0}.txt", options.BlockThresholdUnpopularPassword; // using (StreamWriter detailed = File.AppendText(@filename.ToString())) // { // detailed.WriteLine("The false postive rate is {0}/({0}+{1}) ({2:F20}%)", stats.FalsePositives, stats.TruePositives, falsePositiveRate * 100d); // detailed.WriteLine("The false negative rate is {0}/({0}+{1}) ({2:F20}%)", stats.FalseNegatives, stats.TrueNegatives, falseNegativeRate * 100d); // detailed.WriteLine("The detection rate is {0}/({0}+{1}) ({2:F20}%)", stats.TruePositives, stats.FalseNegatives, detectionRate * 100d); // detailed.WriteLine("The false detection rate is {0}/{0}+({1}) ({2:F20}%)", stats.FalsePositives, stats.TrueNegatives, falseDetectionRate * 100d); // detailed.WriteLine("Start to catch attacker after {0} requests and attackers have login {1} times into users accounts successfully.", stats.bootstrapall, stats.bootstrapsuccess); // } //} //using (StringWriter filename = new StringWriter()) //{ // // filename.Write("Result.csv", options.BlockThresholdUnpopularPassword); // //string filename = "Detailed_Log_Unpopular{0}.txt", options.BlockThresholdUnpopularPassword; // using (StreamWriter CSV = File.AppendText(@"ResultDetail.csv")) // { // CSV.WriteLine("{0},{1},{2},{3},{4},{5},{6}, {7}", options.PenaltyForInvalidAccount, falsePositiveRate * 100d, // falseNegativeRate * 100d, detectionRate * 100d, falseDetectionRate * 100d, stats.bootstrapall, stats.bootstrapsuccess, falsePositiveRate * 10000d); // } //} } sw.Stop(); Console.WriteLine("Time Elapsed={0}", sw.Elapsed); Console.WriteLine("the new count is {0}", stats.MaliciousCount + stats.BenignCount); //falsePositiveRate = ((double)stats.FalsePositives) / ((double)stats.FalsePositives + stats.TruePositives); //falseNegativeRate = ((double)stats.FalseNegatives) / ((double)stats.FalseNegatives + stats.TrueNegatives); //using (System.IO.StreamWriter file = //new System.IO.StreamWriter(@"result_log.txt")) //{ // file.WriteLine("The false postive rate is {0}/({0}+{1}) ({2:F20}%)", stats.FalsePositives, stats.TruePositives, falsePositiveRate * 100d); // file.WriteLine("The false negative rate is {0}/({0}+{1}) ({2:F20}%)", stats.FalseNegatives, stats.TrueNegatives, falseNegativeRate * 100d); // file.WriteLine("Time Elapsed={0}", sw.Elapsed); //} using (StringWriter filename = new StringWriter()) { // filename.Write("Result.csv", options.BlockThresholdUnpopularPassword); if (ParameterSweep == "BlockThresholdUnpopularPassword") { string csvname = "Log_BlockThresholdUnpopularPassword.csv"; using (StreamWriter CSV = File.AppendText(@csvname)) { CSV.WriteLine("{0},{1},{2},{3},{4},{5},{6},{7}", options.BlockThresholdUnpopularPassword, falsePositiveRate * 100d, falseNegativeRate * 100d, detectionRate * 100d, falseDetectionRate * 100d, stats.bootstrapall, stats.bootstrapsuccess, falsePositiveRate * 10000d); } } else if (ParameterSweep == "BlockThresholdPopularPassword") { string csvname = "Log_BlockThresholdPopularPassword.csv"; using (StreamWriter CSV = File.AppendText(@csvname)) { CSV.WriteLine("{0},{1},{2},{3},{4},{5},{6},{7}", options.BlockThresholdPopularPassword, falsePositiveRate * 100d, falseNegativeRate * 100d, detectionRate * 100d, falseDetectionRate * 100d, stats.bootstrapall, stats.bootstrapsuccess, falsePositiveRate * 10000d); } } else if (ParameterSweep == "PenaltyForInvalidAccount") { string csvname = "Log_PenaltyForInvalidAccount.csv"; using (StreamWriter CSV = File.AppendText(@csvname)) { CSV.WriteLine("{0},{1},{2},{3},{4},{5},{6},{7}", options.PenaltyForInvalidAccount, falsePositiveRate * 100d, falseNegativeRate * 100d, detectionRate * 100d, falseDetectionRate * 100d, stats.bootstrapall, stats.bootstrapsuccess, falsePositiveRate * 10000d); } } else if (ParameterSweep == "RewardForCorrectPasswordPerAccount") { string csvname = "RewardForCorrectPasswordPerAccount.csv"; using (StreamWriter CSV = File.AppendText(@csvname)) { CSV.WriteLine("{0},{1},{2},{3},{4},{5},{6},{7}", options.RewardForCorrectPasswordPerAccount, falsePositiveRate * 100d, falseNegativeRate * 100d, detectionRate * 100d, falseDetectionRate * 100d, stats.bootstrapall, stats.bootstrapsuccess, falsePositiveRate * 10000d); } } else if (ParameterSweep == "PenaltyForReachingEachPopularityThreshold") { string csvname = "PenaltyForReachingEachPopularityThreshold.csv"; using (StreamWriter CSV = File.AppendText(@csvname)) { CSV.WriteLine("{0},{1},{2},{3},{4},{5},{6},{7}", 1, falsePositiveRate * 100d, falseNegativeRate * 100d, detectionRate * 100d, falseDetectionRate * 100d, stats.bootstrapall, stats.bootstrapsuccess, falsePositiveRate * 10000d); } } } }